Html5 canvas 在动画HTML5画布中缩放和平移

Html5 canvas 在动画HTML5画布中缩放和平移,html5-canvas,zooming,panning,Html5 Canvas,Zooming,Panning,我有一张地图。我希望用户能够缩放和平移地图。想象一下谷歌地图,它不是无限可平移的,而是一个正方形(如果你越过它的边缘,它就不会再环绕) 我已经使用scale()和translate()实现了缩放和平移。这些很好用 我被困在最后一部分——当用户缩放时,我想围绕该点居中缩放。这很难用语言来解释,所以想象一下当你在谷歌地图上鼠标滚轮时会发生什么——这就是我想要的 我已经看过了每一个答案,在标题中有这些术语。大多数是上的变体,基本上说这就是我需要做的: ctx.translate(/* to the p

我有一张地图。我希望用户能够缩放和平移地图。想象一下谷歌地图,它不是无限可平移的,而是一个正方形(如果你越过它的边缘,它就不会再环绕)

我已经使用
scale()
translate()
实现了缩放和平移。这些很好用

我被困在最后一部分——当用户缩放时,我想围绕该点居中缩放。这很难用语言来解释,所以想象一下当你在谷歌地图上鼠标滚轮时会发生什么——这就是我想要的

我已经看过了每一个答案,在标题中有这些术语。大多数是上的变体,基本上说这就是我需要做的:

ctx.translate(/* to the point where the mouse is */);
ctx.scale(/* to zoom level I want */)
ctx.translate(/* back to the point where the mouse was, taking zoom into account */);
然而,无论我做什么,我似乎都无法让它发挥作用。我可以让它在缩放后缩放到一个特定的点,但无论我做什么,我都无法使该点与鼠标指针所在的位置相等

退房。想象一下,广场是一张地图,圆圈是国家或其他什么

我发现最好的实现是和链接。但是,该代码使用了SVG和
.createSVGMatrix()
,以及坦率地说,我无法理解的各种东西。如果可能的话,我更喜欢完全画布式的解决方案

很明显,我对图书馆不感兴趣。我想了解为什么我正在做的事情不起作用。

这里有一种在某一点进行缩放的技术:

绘制地图

通过不使用变换来绘制地图来简化事情(不需要平移、缩放!)

所需要的只是
context.drawImage
的缩放版本

您要做的是将原始地图缩放到所需的大小,然后从用户选择的缩放点向上和向左拉动它

context.drawImage(
    map,
    0,0,map.width,map.height,  // start with the map at original (unscaled) size
    offsetX,offsetY,           // pull the map leftward & upward from the scaling point
    scaledWidth,scaledHeight   // resize the map to the currently scaled size
选择缩放点(焦点):

缩放焦点实际上是2个点

第一个焦点是mouseX,mouseY,用户在其中单击以设置所需的缩放点。请务必记住,鼠标坐标位于缩放空间中。用户正在查看/单击的地图被缩放,因此他们的mouseX、mouseY也被缩放

通过取消缩放鼠标坐标计算第二个焦点。第二个点是原始未缩放贴图上的等效鼠标位置

第二个未缩放的焦点用于计算从第一个焦点向左和向上拉动缩放贴图的量

function setFocus(mx,my){
    // mouseX,mouseY is the scaling point in scaled coordinates
    focusX=mx;
    focusY=my;
    // convert the scaled focal point
    // to an unscaled focal point
    focusX1=parseInt((mx-mapLeft)/scale);
    focusY1=parseInt((my-mapTop)/scale);
}
缩放地图

当用户表示要放大或缩小地图时:

  • 计算新的缩放贴图宽度和高度
  • 计算从缩放点向上和向左拉动新缩放贴图所需的偏移量(缩放点以前是通过鼠标位置选择的)
代码:

下面是示例代码和演示:

var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
var$canvas=$(“#canvas”);
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
//
var计数器=1;
var PI2=数学PI*2;
var-iw,ih;
var mapLeft、mapTop、mapWidth、mapHeight;
变量focusX,focusY,focusX1,focusY1;
var量表;
var map=新图像();
map.onload=start;
map.src=”https://dl.dropboxusercontent.com/u/139992952/multple/mapSmall.png";
函数start(){
iw=地图宽度;
ih=地图高度;
//首字母
mapLeft=0;
mapTop=0;
比例=1.00;
设置焦点(iw/2*刻度,ih/2*刻度);
设置比例(比例);//还设置贴图宽度、贴图高度
drawMap();
//
$(“#canvas”).mousedown(函数(e){handleMouseDown(e);});
//
canvas.addEventListener('DOMMouseScroll',handleScroll,false);
canvas.addEventListener('mousewheel',handleScroll,false);
}
//
函数设置刻度(新闻刻度){
规模=新闻规模;
mapWidth=parseInt(iw*比例);
mapHeight=parseInt(ih*比例);
mapLeft=parseInt(focusX-focusX1*scale);
mapTop=parseInt(focusY-focusY1*比例);
drawMap();
}
//
函数设置焦点(mx,my){
//mouseX,mouseY是缩放坐标中的缩放点
focusX=mx;
focusY=my;
//转换缩放的焦点
//到一个没有标度的焦点
focusX1=parseInt((mx-mapLeft)/比例);
focusY1=parseInt((我的地图顶部)/比例);
//
drawMap();
}
//
函数drawMap(){
clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.drawImage(地图,0,0,iw,ih,mapLeft,mapTop,地图宽度,地图高度);
圆点(ctx、聚焦X、聚焦Y,“红色”);
ctx.restore();
}
功能点(ctx、x、y、填充){
ctx.beginPath();
弧(x,y,4,0,PI2);
ctx.closePath();
ctx.fillStyle=填充;
ctx.fill();
ctx.线宽=2;
ctx.stroke();
}
//
函数handleScroll(e){
e、 预防默认值();
e、 停止传播();
var delta=e.wheelDelta?e.wheelDelta/30:e.detail?-e.detail:0;
if(增量){
计数器+=增量;
设置刻度(1+计数器/100);
}
};
//
功能手柄向下(e){
e、 预防默认值();
e、 停止传播();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(例如clientY-offsetY);
设置焦点(mouseX、mouseY);
drawMap();
}
body{背景色:象牙;}
画布{边框:1px纯红;}

单击以设置缩放点
使用鼠标滚轮进行缩放

我最近做了一些类似的事情,希望它是相关的(如果没有你的代码,我认为这可能是“回译”中的一个数学错误(你也必须缩放点))哦,这看起来很有趣!谢谢,我现在就去看看。真不敢相信我居然漏掉了那个问题。我想我不应该只搜索“画布”解决方案。这是一个非常酷的方法,但我认为它不适用于我的情况。我的地图不是图像,而是使用画布动态绘制的(首先,它是动画的,所以这是不可协商的)。回想起来,“像谷歌地图”这件事可能有点像是在转移视线,因为我没有使用图像:-/这种方法适用于动态绘制的画布。只需在mem中创建第二个
function setScale(newScale){
    scale=newScale;
    // calc the width & height of the newly scaled map
    mapWidth=parseInt(iw*scale);
    mapHeight=parseInt(ih*scale);
    // calc how much to offset the map on the canvas
    mapLeft=parseInt(focusX-focusX1*scale);
    mapTop =parseInt(focusY-focusY1*scale);
    // draw the map
    drawMap();
}