Phóng to một điểm (sử dụng tỷ lệ và dịch)


156

Tôi muốn có thể phóng to điểm dưới chuột trong khung vẽ HTML 5, như phóng to Google Maps . Làm thế nào tôi có thể đạt được điều đó?


2
Tôi đã sử dụng điều này để phóng to canvas của tôi và nó hoạt động rất tốt! Điều duy nhất tôi phải thêm là, việc tính toán mức thu phóng không như bạn mong đợi. "var zoom = 1 + bánh xe / 2;" tức là kết quả này là 1,5 để phóng to và 0,5 cho thu nhỏ. Tôi đã chỉnh sửa điều này trong phiên bản của mình để tôi có 1,5 để phóng to và 1 / 1,5 cho thu nhỏ, điều này làm cho số lượng phóng to và thu nhỏ bằng nhau. Vì vậy, nếu bạn phóng to một lần và phóng to lại, bạn sẽ có cùng một hình ảnh như trước khi phóng to.
Chris

2
Lưu ý rằng điều này không hoạt động trên Firefox, nhưng phương pháp này có thể dễ dàng được áp dụng cho plugin mousewheel jQuery . Cám ơn vì đã chia sẻ!
johndodo

2
var zoom = Math.pow (1.5f, bánh xe); // Sử dụng điều này để tính toán thu phóng. Nó có lợi ích là thu phóng theo bánh xe = 2 giống như thu phóng hai lần bởi bánh xe = 1. Ngoài ra, phóng to +2 và ra +2 sẽ khôi phục tỷ lệ ban đầu.
Matt

Câu trả lời:


126

Giải pháp tốt hơn là chỉ cần di chuyển vị trí của khung nhìn dựa trên sự thay đổi trong thu phóng. Điểm thu phóng chỉ đơn giản là điểm trong thu phóng cũ và mức thu phóng mới mà bạn muốn giữ nguyên. Nghĩa là chế độ xem được phóng to trước và chế độ xem sau thu phóng có cùng số zoompoint so với chế độ xem. Cho rằng chúng tôi mở rộng liên quan đến nguồn gốc. Bạn có thể điều chỉnh vị trí khung nhìn phù hợp:

scalechange = newscale - oldscale;
offsetX = -(zoomPointX * scalechange);
offsetY = -(zoomPointY * scalechange);

Vì vậy, thực sự bạn chỉ có thể xoay xuống và sang phải khi bạn phóng to, theo hệ số bạn đã phóng to bao nhiêu, so với điểm bạn đã phóng to.

nhập mô tả hình ảnh ở đây


2
Có giá trị hơn mã cắt và dán là giải thích về giải pháp tốt nhất là gì và tại sao nó hoạt động mà không có hành lý đặc biệt là nếu nó dài ba dòng.
Tatarize

2
scalechange = newscale / oldscale?
Tejesh Alimilli

4
Ngoài ra, tôi muốn thêm cho những người đang tìm cách đạt được một bản đồ như thành phần thu phóng pan, rằng chuột X, Y phải là (mousePosRelativeToContainer - currentTransform) / currentScale nếu không nó sẽ coi vị trí chuột hiện tại là liên quan đến thùng chứa.
Gilad

1
Vâng, toán học này giả định rằng zoom cũng như pan nằm trong các coords có liên quan đến nguồn gốc. Nếu chúng liên quan đến khung nhìn, bạn phải điều chỉnh chúng cho phù hợp. Mặc dù tôi cho rằng toán học chính xác là zoomPoint = (mousePosRelativeToContainer + currentTranslation). Toán học này cũng giả sử điểm gốc thường ở phía trên bên trái của trường. Nhưng, điều chỉnh cho các tình huống hơi không điển hình sẽ dễ dàng hơn nhiều vì sự đơn giản.
Tatarize

1
@ C.Finke Cách thứ hai có thể được thực hiện là sử dụng các bản dịch trong ctx. Bạn vẽ mọi thứ có cùng kích thước và ở cùng một vị trí. Nhưng, bạn chỉ cần sử dụng phép nhân ma trận trong khung hình javascript để đặt pan và tỷ lệ (thu phóng) của bối cảnh. Vì vậy, thay vì vẽ lại tất cả các hình dạng ở một vị trí khác nhau. Bạn vẽ chúng ở cùng một vị trí và di chuyển khung nhìn trong javascript. Phương pháp này cũng sẽ yêu cầu bạn lấy các sự kiện chuột và dịch ngược lại. Vì vậy, bạn trừ đi chảo, sau đó đảo ngược hệ số bằng thu phóng.
Tatarize

67

Cuối cùng đã giải quyết nó:

var zoomIntensity = 0.2;

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = 600;
var height = 200;

var scale = 1;
var originx = 0;
var originy = 0;
var visibleWidth = width;
var visibleHeight = height;


function draw(){
    // Clear screen to white.
    context.fillStyle = "white";
    context.fillRect(originx,originy,800/scale,600/scale);
    // Draw the black square.
    context.fillStyle = "black";
    context.fillRect(50,50,100,100);
}
// Draw loop at 60FPS.
setInterval(draw, 1000/60);

canvas.onwheel = function (event){
    event.preventDefault();
    // Get mouse offset.
    var mousex = event.clientX - canvas.offsetLeft;
    var mousey = event.clientY - canvas.offsetTop;
    // Normalize wheel to +1 or -1.
    var wheel = event.deltaY < 0 ? 1 : -1;

    // Compute zoom factor.
    var zoom = Math.exp(wheel*zoomIntensity);
    
    // Translate so the visible origin is at the context's origin.
    context.translate(originx, originy);
  
    // Compute the new visible origin. Originally the mouse is at a
    // distance mouse/scale from the corner, we want the point under
    // the mouse to remain in the same place after the zoom, but this
    // is at mouse/new_scale away from the corner. Therefore we need to
    // shift the origin (coordinates of the corner) to account for this.
    originx -= mousex/(scale*zoom) - mousex/scale;
    originy -= mousey/(scale*zoom) - mousey/scale;
    
    // Scale it (centered around the origin due to the trasnslate above).
    context.scale(zoom, zoom);
    // Offset the visible origin to it's proper position.
    context.translate(-originx, -originy);

    // Update scale and others.
    scale *= zoom;
    visibleWidth = width / scale;
    visibleHeight = height / scale;
}
<canvas id="canvas" width="600" height="200"></canvas>

Chìa khóa, như @Tatarize đã chỉ ra , là tính toán vị trí trục sao cho điểm thu phóng (con trỏ chuột) vẫn ở cùng một vị trí sau khi thu phóng.

Ban đầu con chuột ở một khoảng cách mouse/scaletừ góc, chúng tôi muốn điểm dưới con chuột vẫn ở cùng một vị trí sau khi phóng to, nhưng điều này nằm ở mouse/new_scalegóc xa. Do đó, chúng ta cần chuyển origin(tọa độ của góc) để giải thích cho việc này.

originx -= mousex/(scale*zoom) - mousex/scale;
originy -= mousey/(scale*zoom) - mousey/scale;
scale *= zoom

Đoạn mã còn lại sau đó cần áp dụng tỷ lệ và dịch sang ngữ cảnh vẽ sao cho nguồn gốc của nó trùng với góc canvas.


Cảm ơn anh bạn, gần như đã mất 2 ngày, trước khi tìm thấy mã của bạn
Velaro

Này, tôi chỉ đang tìm kiếm một cái gì đó như thế này và chỉ muốn nói rằng bạn đã bẻ khóa nó!
chrisallick

26

Đây thực sự là một vấn đề rất khó khăn (về mặt toán học) và tôi đang làm việc với điều tương tự. Tôi đã hỏi một câu hỏi tương tự trên Stackoverflow nhưng không có phản hồi, nhưng được đăng trong DocType (StackOverflow cho HTML / CSS) và nhận được phản hồi. Hãy xem http://doctype.com/javascript-image-zoom-css3-transforms-calculate-origin-example

Tôi đang trong quá trình xây dựng một plugin jQuery thực hiện việc này (thu phóng kiểu Google Maps bằng CSS3 Transforms). Tôi đã thu phóng bit để con trỏ chuột hoạt động tốt, vẫn cố gắng tìm ra cách cho phép người dùng kéo khung vẽ xung quanh như bạn có thể làm trong Google Maps. Khi tôi làm việc, tôi sẽ đăng mã ở đây, nhưng hãy kiểm tra liên kết ở trên để biết phần thu phóng chuột đến điểm.

Tôi không nhận ra có các phương pháp tỷ lệ và dịch trên ngữ cảnh Canvas, bạn có thể đạt được điều tương tự bằng CSS3, vd. sử dụng jQuery:

$('div.canvasContainer > canvas')
    .css('-moz-transform', 'scale(1) translate(0px, 0px)')
    .css('-webkit-transform', 'scale(1) translate(0px, 0px)')
    .css('-o-transform', 'scale(1) translate(0px, 0px)')
    .css('transform', 'scale(1) translate(0px, 0px)');

Đảm bảo rằng bạn đặt biến đổi gốc CSS3 thành 0, 0 (-moz-Transform-origin: 0 0). Sử dụng biến đổi CSS3 cho phép bạn phóng to bất cứ thứ gì, chỉ cần đảm bảo rằng DIV của container được đặt thành tràn: ẩn để ngăn các cạnh được phóng to tràn ra khỏi các cạnh.

Cho dù bạn sử dụng các phép biến đổi CSS3, hay các phương thức dịch và tỷ lệ riêng của canvas đều tùy thuộc vào bạn, nhưng hãy kiểm tra liên kết ở trên để biết các phép tính.


Cập nhật: Meh! Tôi sẽ chỉ đăng mã ở đây chứ không phải để bạn theo liên kết:

$(document).ready(function()
{
    var scale = 1;  // scale of the image
    var xLast = 0;  // last x location on the screen
    var yLast = 0;  // last y location on the screen
    var xImage = 0; // last x location on the image
    var yImage = 0; // last y location on the image

    // if mousewheel is moved
    $("#mosaicContainer").mousewheel(function(e, delta)
    {
        // find current location on screen 
        var xScreen = e.pageX - $(this).offset().left;
        var yScreen = e.pageY - $(this).offset().top;

        // find current location on the image at the current scale
        xImage = xImage + ((xScreen - xLast) / scale);
        yImage = yImage + ((yScreen - yLast) / scale);

        // determine the new scale
        if (delta > 0)
        {
            scale *= 2;
        }
        else
        {
            scale /= 2;
        }
        scale = scale < 1 ? 1 : (scale > 64 ? 64 : scale);

        // determine the location on the screen at the new scale
        var xNew = (xScreen - xImage) / scale;
        var yNew = (yScreen - yImage) / scale;

        // save the current screen location
        xLast = xScreen;
        yLast = yScreen;

        // redraw
        $(this).find('div').css('-moz-transform', 'scale(' + scale + ')' + 'translate(' + xNew + 'px, ' + yNew + 'px' + ')')
                           .css('-moz-transform-origin', xImage + 'px ' + yImage + 'px')
        return false;
    });
});

Tất nhiên bạn sẽ cần phải điều chỉnh nó để sử dụng quy mô canvas và phương thức dịch.


Cập nhật 2: Chỉ cần lưu ý rằng tôi đang sử dụng biến đổi gốc cùng với dịch. Tôi đã quản lý để triển khai một phiên bản chỉ sử dụng tỷ lệ và tự dịch, hãy kiểm tra nó tại đây http://www.dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html Đợi hình ảnh tải xuống rồi sử dụng bánh xe chuột để phóng to, cũng hỗ trợ di chuyển bằng cách kéo hình ảnh xung quanh. Đó là sử dụng Chuyển đổi CSS3 nhưng bạn sẽ có thể sử dụng các phép tính tương tự cho Canvas của mình.


Cuối cùng tôi cũng giải quyết được, mất 3 phút bây giờ sau khoảng 2 tuần làm việc khác
csiz

@Synday Liên kết Ironfoot trên bản cập nhật của anh ấy không hoạt động. Liên kết này: dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html tôi muốn sự thúc đẩy này. Bạn có thể gửi mã ở đây? cảm ơn
Bogz

2
kể từ hôm nay (sept.2014), liên kết đến MosaicTest.html đã chết.
Chris

bản demo khảm đã biến mất. Tôi thường sử dụng vanilla js và không phải jQuery. $ (cái này) đề cập đến là gì? tài liệu.body.offsetTop? Tôi thực sự muốn xem bản demo khảm dự án everscape.com của tôi thực sự có thể được hưởng lợi từ nó.
FlavorScape

2
Trang thử nghiệm khảm được lưu trên archive.org: web.archive.org/web/20130126152008/http://th
Chris

9

Tôi gặp phải vấn đề này khi sử dụng c ++, điều mà có lẽ tôi không nên sử dụng ma trận OpenGL để bắt đầu với ... dù sao đi nữa, nếu bạn đang sử dụng một điều khiển có nguồn gốc là góc trên cùng bên trái và bạn muốn xoay / thu phóng như google maps, đây là cách bố trí (sử dụng allegro làm trình xử lý sự kiện của tôi):

// initialize
double originx = 0; // or whatever its base offset is
double originy = 0; // or whatever its base offset is
double zoom = 1;

.
.
.

main(){

    // ...set up your window with whatever
    //  tool you want, load resources, etc

    .
    .
    .
    while (running){
        /* Pan */
        /* Left button scrolls. */
        if (mouse == 1) {
            // get the translation (in window coordinates)
            double scroll_x = event.mouse.dx; // (x2-x1) 
            double scroll_y = event.mouse.dy; // (y2-y1) 

            // Translate the origin of the element (in window coordinates)      
            originx += scroll_x;
            originy += scroll_y;
        }

        /* Zoom */ 
        /* Mouse wheel zooms */
        if (event.mouse.dz!=0){    
            // Get the position of the mouse with respect to 
            //  the origin of the map (or image or whatever).
            // Let us call these the map coordinates
            double mouse_x = event.mouse.x - originx;
            double mouse_y = event.mouse.y - originy;

            lastzoom = zoom;

            // your zoom function 
            zoom += event.mouse.dz * 0.3 * zoom;

            // Get the position of the mouse
            // in map coordinates after scaling
            double newx = mouse_x * (zoom/lastzoom);
            double newy = mouse_y * (zoom/lastzoom);

            // reverse the translation caused by scaling
            originx += mouse_x - newx;
            originy += mouse_y - newy;
        }
    }
}  

.
.
.

draw(originx,originy,zoom){
    // NOTE:The following is pseudocode
    //          the point is that this method applies so long as
    //          your object scales around its top-left corner
    //          when you multiply it by zoom without applying a translation.

    // draw your object by first scaling...
    object.width = object.width * zoom;
    object.height = object.height * zoom;

    //  then translating...
    object.X = originx;
    object.Y = originy; 
}

9

Tôi thích câu trả lời của Tatarize , nhưng tôi sẽ cung cấp một giải pháp thay thế. Đây là một vấn đề đại số tuyến tính tầm thường và phương pháp tôi trình bày hoạt động tốt với pan, zoom, skew, v.v. Đó là, nó hoạt động tốt nếu hình ảnh của bạn đã được chuyển đổi.

Khi một ma trận được chia tỷ lệ, thang đo nằm ở điểm (0, 0). Vì vậy, nếu bạn có một hình ảnh và chia tỷ lệ của nó theo hệ số 2, điểm dưới cùng bên phải sẽ tăng gấp đôi theo cả hai hướng x và y (sử dụng quy ước rằng [0, 0] là trên cùng bên trái của hình ảnh).

Nếu thay vào đó, bạn muốn phóng to hình ảnh về trung tâm, thì một giải pháp như sau: (1) dịch hình ảnh sao cho tâm của nó ở (0, 0); (2) chia tỷ lệ hình ảnh theo các yếu tố x và y; (3) dịch lại hình ảnh. I E

myMatrix
  .translate(image.width / 2, image.height / 2)    // 3
  .scale(xFactor, yFactor)                         // 2
  .translate(-image.width / 2, -image.height / 2); // 1

Trừu tượng hơn, chiến lược tương tự làm việc cho bất kỳ điểm nào. Ví dụ, nếu bạn muốn chia tỷ lệ hình ảnh tại một điểm P:

myMatrix
  .translate(P.x, P.y)
  .scale(xFactor, yFactor)
  .translate(-P.x, -P.y);

Và cuối cùng, nếu hình ảnh đã được chuyển đổi theo một cách nào đó (ví dụ: nếu nó bị xoay, lệch, dịch hoặc thu nhỏ), thì việc chuyển đổi hiện tại cần được giữ nguyên. Cụ thể, biến đổi được xác định ở trên cần được nhân sau (hoặc nhân phải) bởi biến đổi hiện tại.

myMatrix
  .translate(P.x, P.y)
  .scale(xFactor, yFactor)
  .translate(-P.x, -P.y)
  .multiply(myMatrix);

Có bạn có nó. Đây là một plunk cho thấy điều này trong hành động. Di chuyển bằng con lăn trên các chấm và bạn sẽ thấy rằng chúng luôn được đặt. (Chỉ được thử nghiệm trong Chrome.) Http://plnkr.co/edit/3aqsWHPLlSXJ9JCcJzgH?p=preview


1
Tôi phải nói rằng, nếu bạn có sẵn một ma trận biến đổi affine, hãy sử dụng nó với sự nhiệt tình. Rất nhiều ma trận biến đổi thậm chí sẽ có các hàm zoom (sx, sy, x, y) thực hiện chính xác điều đó. Nó gần như đáng để nấu một cái nếu bạn không cho một cái để sử dụng.
Tatarize

Trong thực tế, tôi thú nhận rằng trong mã tôi đã sử dụng giải pháp này, đã được thay thế bằng một lớp ma trận. Và tôi đã thực hiện điều chính xác này nhiều lần và đã nấu các lớp ma trận không dưới hai lần. ( Github.com/EmbroidePy/pyembroidery/blob/master/pyembroidery/... ), ( github.com/EmbroidePy/EmbroidePy/blob/master/embroidepy/... ). Nếu bạn muốn bất cứ điều gì phức tạp hơn chính xác các thao tác này, thì ma trận về cơ bản là câu trả lời chính xác và một khi bạn đã xử lý được đại số tuyến tính, bạn nhận ra câu trả lời này thực sự là câu trả lời tốt nhất.
Tatarize

6

Đây là giải pháp của tôi cho hình ảnh hướng trung tâm:

var MIN_SCALE = 1;
var MAX_SCALE = 5;
var scale = MIN_SCALE;

var offsetX = 0;
var offsetY = 0;

var $image     = $('#myImage');
var $container = $('#container');

var areaWidth  = $container.width();
var areaHeight = $container.height();

$container.on('wheel', function(event) {
    event.preventDefault();
    var clientX = event.originalEvent.pageX - $container.offset().left;
    var clientY = event.originalEvent.pageY - $container.offset().top;

    var nextScale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, scale - event.originalEvent.deltaY / 100));

    var percentXInCurrentBox = clientX / areaWidth;
    var percentYInCurrentBox = clientY / areaHeight;

    var currentBoxWidth  = areaWidth / scale;
    var currentBoxHeight = areaHeight / scale;

    var nextBoxWidth  = areaWidth / nextScale;
    var nextBoxHeight = areaHeight / nextScale;

    var deltaX = (nextBoxWidth - currentBoxWidth) * (percentXInCurrentBox - 0.5);
    var deltaY = (nextBoxHeight - currentBoxHeight) * (percentYInCurrentBox - 0.5);

    var nextOffsetX = offsetX - deltaX;
    var nextOffsetY = offsetY - deltaY;

    $image.css({
        transform : 'scale(' + nextScale + ')',
        left      : -1 * nextOffsetX * nextScale,
        right     : nextOffsetX * nextScale,
        top       : -1 * nextOffsetY * nextScale,
        bottom    : nextOffsetY * nextScale
    });

    offsetX = nextOffsetX;
    offsetY = nextOffsetY;
    scale   = nextScale;
});
body {
    background-color: orange;
}
#container {
    margin: 30px;
    width: 500px;
    height: 500px;
    background-color: white;
    position: relative;
    overflow: hidden;
}
img {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    max-width: 100%;
    max-height: 100%;
    margin: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id="container">
    <img id="myImage" src="http://s18.postimg.org/eplac6dbd/mountain.jpg">
</div>


4

Đây là một cách khác để làm điều đó sử dụng setTransform () thay vì scale () và dịch (). Tất cả mọi thứ được lưu trữ trong cùng một đối tượng. Canvas được giả định là 0,0 trên trang, nếu không, bạn sẽ cần phải trừ vị trí của nó khỏi các cuộn trang.

this.zoomIn = function (pageX, pageY) {
    var zoomFactor = 1.1;
    this.scale = this.scale * zoomFactor;
    this.lastTranslation = {
        x: pageX - (pageX - this.lastTranslation.x) * zoomFactor,
        y: pageY - (pageY - this.lastTranslation.y) * zoomFactor
    };
    this.canvasContext.setTransform(this.scale, 0, 0, this.scale,
                                    this.lastTranslation.x,
                                    this.lastTranslation.y);
};
this.zoomOut = function (pageX, pageY) {
    var zoomFactor = 1.1;
    this.scale = this.scale / zoomFactor;
    this.lastTranslation = {
        x: pageX - (pageX - this.lastTranslation.x) / zoomFactor,
        y: pageY - (pageY - this.lastTranslation.y) / zoomFactor
    };
    this.canvasContext.setTransform(this.scale, 0, 0, this.scale,
                                    this.lastTranslation.x,
                                    this.lastTranslation.y);
};

Mã kèm theo để xử lý panning:

this.startPan = function (pageX, pageY) {
    this.startTranslation = {
        x: pageX - this.lastTranslation.x,
        y: pageY - this.lastTranslation.y
    };
};
this.continuePan = function (pageX, pageY) {
    var newTranslation = {x: pageX - this.startTranslation.x,
                          y: pageY - this.startTranslation.y};
    this.canvasContext.setTransform(this.scale, 0, 0, this.scale,
                                    newTranslation.x, newTranslation.y);
};
this.endPan = function (pageX, pageY) {
    this.lastTranslation = {
        x: pageX - this.startTranslation.x,
        y: pageY - this.startTranslation.y
    };
};

Để tự mình rút ra câu trả lời, hãy xem xét rằng các tọa độ trang giống nhau cần khớp với cùng tọa độ canvas trước và sau khi thu phóng. Sau đó, bạn có thể làm một số đại số bắt đầu từ phương trình này:

(pageCoords - dịch) / scale = canvasCoords


3

Tôi muốn đặt ở đây một số thông tin cho những người, những người thực hiện vẽ riêng hình ảnh và di chuyển - hiển thị nó.

Điều này có thể hữu ích khi bạn muốn lưu trữ thu phóng và vị trí của chế độ xem.

Đây là ngăn kéo:

function redraw_ctx(){
   self.ctx.clearRect(0,0,canvas_width, canvas_height)
   self.ctx.save()
   self.ctx.scale(self.data.zoom, self.data.zoom) // 
   self.ctx.translate(self.data.position.left, self.data.position.top) // position second
   // Here We draw useful scene My task - image:
   self.ctx.drawImage(self.img ,0,0) // position 0,0 - we already prepared
   self.ctx.restore(); // Restore!!!
}

Thông báo quy mô PHẢI là đầu tiên .

Và đây là zoomer:

function zoom(zf, px, py){
    // zf - is a zoom factor, which in my case was one of (0.1, -0.1)
    // px, py coordinates - is point within canvas 
    // eg. px = evt.clientX - canvas.offset().left
    // py = evt.clientY - canvas.offset().top
    var z = self.data.zoom;
    var x = self.data.position.left;
    var y = self.data.position.top;

    var nz = z + zf; // getting new zoom
    var K = (z*z + z*zf) // putting some magic

    var nx = x - ( (px*zf) / K ); 
    var ny = y - ( (py*zf) / K);

    self.data.position.left = nx; // renew positions
    self.data.position.top = ny;   
    self.data.zoom = nz; // ... and zoom
    self.redraw_ctx(); // redraw context
    }

và, tất nhiên, chúng ta sẽ cần một trình kéo:

this.my_cont.mousemove(function(evt){
    if (is_drag){
        var cur_pos = {x: evt.clientX - off.left,
                       y: evt.clientY - off.top}
        var diff = {x: cur_pos.x - old_pos.x,
                    y: cur_pos.y - old_pos.y}

        self.data.position.left += (diff.x / self.data.zoom);  // we want to move the point of cursor strictly
        self.data.position.top += (diff.y / self.data.zoom);

        old_pos = cur_pos;
        self.redraw_ctx();

    }


})

3
if(wheel > 0) {
    this.scale *= 1.1; 
    this.offsetX -= (mouseX - this.offsetX) * (1.1 - 1);
    this.offsetY -= (mouseY - this.offsetY) * (1.1 - 1);
}
else {
    this.scale *= 1/1.1; 
    this.offsetX -= (mouseX - this.offsetX) * (1/1.1 - 1);
    this.offsetY -= (mouseY - this.offsetY) * (1/1.1 - 1);
}

2

Đây là một triển khai mã của câu trả lời của @ tatarize, sử dụng PIXI.js. Tôi có một khung nhìn nhìn vào một phần của một hình ảnh rất lớn (ví dụ: phong cách google maps).

$canvasContainer.on('wheel', function (ev) {

    var scaleDelta = 0.02;
    var currentScale = imageContainer.scale.x;
    var nextScale = currentScale + scaleDelta;

    var offsetX = -(mousePosOnImage.x * scaleDelta);
    var offsetY = -(mousePosOnImage.y * scaleDelta);

    imageContainer.position.x += offsetX;
    imageContainer.position.y += offsetY;

    imageContainer.scale.set(nextScale);

    renderer.render(stage);
});
  • $canvasContainer là thùng chứa html của tôi.
  • imageContainer là thùng chứa PIXI của tôi có hình ảnh trong đó.
  • mousePosOnImage là vị trí chuột liên quan đến toàn bộ hình ảnh (không chỉ cổng xem).

Đây là cách tôi có được vị trí chuột:

  imageContainer.on('mousemove', _.bind(function(ev) {
    mousePosOnImage = ev.data.getLocalPosition(imageContainer);
    mousePosOnViewport.x = ev.data.originalEvent.offsetX;
    mousePosOnViewport.y = ev.data.originalEvent.offsetY;
  },self));

0

Bạn cần lấy điểm trong không gian thế giới (trái ngược với không gian màn hình) trước và sau khi phóng to, sau đó dịch theo delta.

mouse_world_position = to_world_position(mouse_screen_position);
zoom();
mouse_world_position_new = to_world_position(mouse_screen_position);
translation += mouse_world_position_new - mouse_world_position;

Vị trí chuột nằm trong không gian màn hình, vì vậy bạn phải biến đổi nó thành không gian thế giới. Biến đổi đơn giản nên tương tự như thế này:

world_position = screen_position / scale - translation

0

bạn có thể sử dụng chức năng scrollto (x, y) để xử lý vị trí của thanh cuộn ngay đến điểm bạn cần hiển thị sau khi phóng to. Để tìm vị trí của chuột sử dụng event.clientX và event.clientY. Điều này sẽ giúp bạn


0

Một điều quan trọng ... nếu bạn có một cái gì đó như:

body {
  zoom: 0.9;
}

Bạn cần làm cho điều tương đương trong vải:

canvas {
  zoom: 1.1;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.