canvas实现地图放大缩小拖拽

效果图

如图,代码在最下面

前言

实现目标:使用canvas画出地图,且可以缩放,拖拽
个人理解:其实canvas动画就是一次次的擦除重绘,就像是小时候看的动画片,每一帧播的很快,因为视觉停留,看起来像是连续动画而已。

canvas 基础

1.drawImage
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)  //下面的变量名以此为准

后面8个参数比较重要了:前 4 个是定义图像源的切片位置和大小,后 4 个则是定义切片的目标显示位置和大小。
贴个菜鸟链接 大概回顾下canvas drawImage
或者直接看下图canvas实现地图放大缩小拖拽_第1张图片canvas实现地图放大缩小拖拽_第2张图片

拖拽功能

三个事件:onmousedown,onmousemove,onmouseup
大概讲下思路,后面上代码

  • onmousedown 记录鼠标按下的地址,且移动flag=true
  • onmousemove 当移动flag为true时,计算出drawImage需要的参数,并重绘
  • onmouseup 将移动flag置为false

边界条件

当拖拽的时候不能无限的拖动,否则会超出画布,所以需要限制一下 dx, dy, 两个参数

放大与缩小

监听滚轮事件:onmousewheel

  • 缩放时以鼠标所在的点为中心进行缩放,所以需要计算具体的drawImage的8个参数
  • 每次选取图像时就从(0,0)点选取全图,sWidth, sHeight 即为画布大小不需要改变
  • 假设需要变大N倍,那么dWidth=NsWidth, dHeight=NsHeight
  • 然后放置切片位置,dx,dy应始终为负数,将图像显示到画布中

canvas实现地图放大缩小拖拽_第3张图片
如图:红色框是画布, 画布是不动的,我们根据这个看图片怎么放大。

  • 图1:原图,
  • 图2:以原点放大N倍,
  • 图3:将放大的图向左上平移,最终使放大的图片在画布中合适位置。
  • 图4:最终效果
    其中最重要的就是计算左上平移,也就是dx,dy的数值。

定义变量:

  • 放大倍数:imgScale
  • 当前鼠标所在位置也就是缩放中心 pos:{x,y}
  • 当前画布左上移动的位置,即dx,dy的数值:imgX, imgY(默认为0)
  • 缩放后新的左上移动的位置,imgXN,imgYN

以下是公式:

 imgXN = (1-imgScale)*(pos.x-imgX)/imgScale+(pos.x-(pos.x-imgX)/imgScale);
 imgYN = (1-imgScale)*(pos.y-imgY)/imgScale+(pos.y-(pos.y-imgY)/imgScale);

上面公式没有简化,其实如下

 var newPos = {x:((pos.x-imgX)/imgScale).toFixed(2) , y:((pos.y-imgY)/imgScale).toFixed(2)};
 imgXN = (1-imgScale)*newPos.x+(pos.x-newPos.x);
 imgYN = (1-imgScale)*newPos.y+(pos.y-newPos.y);

以上公式不详解了,大意就是:先把鼠标位置相对原图的位置计算出来,然后以该点为中心重新进行缩放(不知道有没有更好的思路呢)

代码

以下源码:


var canvas, context;
var img, imgX = 0, imgY = 0, imgScale = 1;
var MINIMUM_SCALE = 1.0 ,pos={},posl={},dragging = false;


(function int() {
    canvas = document.getElementById('scaleDragCanvas'); //画布对象
    context = canvas.getContext('2d');//画布显示二维图片
    loadImg();
    canvasEventsInit();

})();

function loadImg() {
    img = new Image();
    img.onload = function () {
        drawImage();
    }
    img.src = 'https://static.zhihu.com/liukanshan/images/comics/bg-89c9bdc3.jpg';//刘看山
}

function drawImage() {
    context.clearRect(0, 0, canvas.width, canvas.height);
    // 保证  imgX  在  [img.width*(1-imgScale),0]   区间内
    if(imgX0) {
        imgX=0
    }
    // 保证  imgY   在  [img.height*(1-imgScale),0]   区间内
    if(imgY0) {
        imgY=0
    }


    context.drawImage(
        img, //规定要使用的图像、画布或视频。
        0, 0, //开始剪切的 x 坐标位置。
        img.width, img.height,  //被剪切图像的高度。
        imgX, imgY,//在画布上放置图像的 x 、y坐标位置。
        img.width * imgScale, img.height * imgScale  //要使用的图像的宽度、高度
    );
}

/*事件注册*/
function canvasEventsInit() {
    canvas.onmousedown = function (event) {
        dragging = true;
         pos = windowToCanvas(event.clientX, event.clientY);  //坐标转换,将窗口坐标转换成canvas的坐标

    };
    canvas.onmousemove = function (evt) {  //移动
        if(dragging){
        posl = windowToCanvas(evt.clientX, evt.clientY);
        var x = posl.x - pos.x, y = posl.y - pos.y;
        imgX  += x;
        imgY  += y;
            pos = JSON.parse(JSON.stringify(posl));
        drawImage();  //重新绘制图片
    }

    };
    canvas.onmouseup = function () {
        dragging = false;
    };
    canvas.onmousewheel = canvas.onwheel = function (event) {    //滚轮放大缩小
        var pos = windowToCanvas (event.clientX, event.clientY);
        event.wheelDelta = event.wheelDelta ? event.wheelDelta : (event.deltalY * (-40));  //获取当前鼠标的滚动情况
        var newPos = {x:((pos.x-imgX)/imgScale).toFixed(2) , y:((pos.y-imgY)/imgScale).toFixed(2)};
        if (event.wheelDelta > 0) {// 放大
                imgScale +=0.1;
                imgX = (1-imgScale)*newPos.x+(pos.x-newPos.x);
                imgY = (1-imgScale)*newPos.y+(pos.y-newPos.y);
        } else {//  缩小
            imgScale -=0.1;
            if(imgScale

立个flag,有空封装一下

你可能感兴趣的:(HTML5,canvas)