【问题标题】:How to center and zoom on a clicked point in canvas如何在画布中的单击点上居中和缩放
【发布时间】:2018-03-04 01:31:41
【问题描述】:

我正在使用 HTML 画布构建一个小型地理区域的交互式地图。画布将是使用的地图图像的全宽和全高。地图上会有几个点,当点击一个点时,画布应该以这个点为中心,然后放大它。

到目前为止,我已经尝试过在绘图上下文中使用translate,绘制地图图像,使点击的点位于画布的中心,然后使用scale 进行缩放,如下所示:

var clickX = e.offsetX || (e.pageX - canvas.offsetLeft);
var clickY = e.offsetY || (e.pageY - canvas.offsetTop);

clickedPoint = { x: clickX, y: clickY };

ctx.translate(
    canvas.width/2 - clickedPoint.x,
    canvas.height/2 - clickedPoint.y
);
ctx.scale(2, 2);

但是,当我此时绘制时,图像并没有出现在预期的位置。我猜是因为翻译点在比例函数之后没有对齐,因为没有比例,翻译正确发生,但我似乎无法让它工作 - 谁能解释如何解决这个问题?

编辑:示例链接 - http://staging.clicky.co.uk/canvas/

【问题讨论】:

    标签: javascript html canvas


    【解决方案1】:

    要在画布上的某个点进行缩放和缩放,您必须知道当前缩放/缩放和当前原点。如果您不跟踪此信息,您将无法在画布上的某个点正确缩放。

    如果您有默认为scale = 1origin = {x:0,y:0} 的比例和原点

    // scale  is current scale
    // origin is current origin
    function scaleAt (at, amount) { // at in screen coords amount is amount to scale
        scale *= amount;
        origin.x = at.x - (at.x - origin.x) * amount;
        origin.y = at.y - (at.y - origin.y) * amount;
    };
    
    var scale = 1;
    const origin = {x : 0, y : 0};
    
    
    // in mouse event
    // scale is change in scale
    scaleAt(clickedPoint,2); // scale 2 times at clickedPoint
    // then set the transform
    ctx.setTransform(scale,0,0,scale,origin.x,origin.y)
    

    使用固定比例在画布中心的图像上居中点

    // scale and origin from above code.
    // newScale is absolute scale
    function scaleMoveCenter (point, newScale) { 
        scale = newScale;
        origin.x = canvas.width / 2 - point.x * scale;
        origin.y = canvas.height / 2 - point.y * scale;
    }
    // in mouse event
    scaleMoveCenter (clickedPoint,2);
    // then set the transform
    ctx.setTransform(scale,0,0,scale,origin.x,origin.y)
    

    如果画布已经设置了非默认的比例和原点,则需要在该坐标系中找到该点。

    // 
    const realPos = {};
    realPos.x = (clickedPoint.x - origin.x ) / scale;
    realPos.y = (clickedPoint.y - origin.y ) / scale;
    
    // increase scale by 2
    scaleMoveCenter (realPos ,scale * 2);
    // then set the transform
    ctx.setTransform(scale,0,0,scale,origin.x,origin.y)
    

    【讨论】:

    • 谢谢,我已经设法让它工作了 - 但是我现在正在制作动画以缩放和平移到点击的点。我正在尝试获取默认原点(可能是 0、0)和新原点之间的步骤,并在动画的每一帧处更新它以及新的比例,但我什至没有接近这一分钟..您可以提供的任何建议都会非常有帮助!
    • @jtrich 您可以对比例和原点进行插值,但由于比例是乘数,因此最佳结果需要对原点或比例进行非线性(多项式)插值。但是尝试线性插值,如果比例差异很小,那么您可能会对外观感到满意。
    • 抱歉,解释得不是很好 - 我已经按照您的描述得到了缩放点,但实际上不确定从哪里开始/结束插值!我以为我可以从 0, 0 到点击的点,并考虑每个点的比例,但它还有很长的路要走。我对此还是很陌生,所以如果你能在这里给我一些基础知识,那就太好了,谢谢
    • @jtrich 对不起,但我不确定你在问什么,原点可以在任何地方,取决于你如何渲染图像。通常,您将拥有希望图像中心所在的原点(在移动的开始和结束时),并将图像偏移量渲染为其大小的一半ctx.drawImage(img,- img.width / 2 , -img.height / 2);
    • 这是有道理的,我现在已经调整了这个,所以我的原点目前位于图像的中心。然后当我想放大一个点时,我是否从这个点插入到新位置在当前比例,然后根据每一帧的新比例调整它?还是我需要最终(缩放)比例的点坐标?希望这是有道理的......
    猜你喜欢
    • 2019-01-07
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    • 2011-10-14
    • 2017-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多