JS canvas绘制能拖动和缩放的球

目的:为了将一些数据点集数据展示到页面上,可以使用鼠标缩放和拖动;

是不是有点抽象,那,可以想象一下百度/高德地图上的效果,绘制了一些地形和路标:
- 拖动:可以查看相邻位置和更远位置的地形;
- 缩放:可以更清晰的查看当前位置。

当然了,我要做的并没有地图那么完美和复杂,但是麻雀虽小,该有的基本逻辑也都是有的,今下来,记录一下开发(研究)过程:

【1】 绘制一个支持拖动的球 (gif图没录好,就先用静态图吧)

效果图:
这里写图片描述

关键点分析:
- 利用 canvas.getContext(“2d”)获取2D模型上下文ctx;
- 利用ctx.arc()方法绘制圆形;
- onmousedown,onmousemove, onmouseout分别鼠标的按下事件,移动事件,移开事件。分别捕获按下事件和移动事件产生的x,y坐标(dx, dy // mx, my ),计算偏移量mx - dx , my - dy。
- 鼠标移开事件时,重置鼠标事件。
- 每次绘制之前,都要清空画布区域ctx.clearRect()

代码 (只粘贴了body段,其他部分用模板就行了):

<body>
    <canvas id="can" width="400" height="400"></canvas>
    <div>1 不管是否点中红球,都能拖动; 2 无缩放</div>
    <script type="text/javascript">
        var can = document.getElementById("can");
        var ctx = can.getContext("2d");
        var isDown = false;
        var dx = 0, dy = 0; // 鼠标按下位置的坐标
        var centerx = 50, centery = 50;  // 圆心坐标 

        // 创建圆,  圆心坐标: x,y
        function createBlock(x, y) {
            ctx.clearRect(0, 0, can.width, can.height);
            ctx.beginPath();
            ctx.fillStyle = "red";
            ctx.arc(x, y, 30, 0, Math.PI * 2);
            ctx.fill();
        }

        // 鼠标按下,将鼠标按下坐标保存在x,y中  
        createBlock(centerx, centery);
        can.onmousedown = function(ev) {
            var e = ev || event;
            dx = e.clientX;
            dy = e.clientY;
            isDown = true;
            can.onmousemove = function(ev) {
                if (isDown) {
                    var e = ev || event;
                    var mx = e.clientX;
                    var my = e.clientY;

                    var _x = mx - dx; // 偏移量x
                    var _y = my - dy; // 偏移量y

                    createBlock((centerx + _x), (centery + _y));
                }
            };
            //鼠标移开事件  
            can.onmouseup = function(ev) {
                isDown = false;
                var e = ev || event;
                centerx += (e.clientX - dx);
                centery += (e.clientY - dy);

                // 重置
                can.onmousemove = null;
                can.onmouseup = null;
            };
        };

    </script>

</body>
只能拖动并不能满足一开始的需求,所以还要添加缩放,缩放的话,单独处理的话,很容易,但和拖动一同处理的话,还是有坑的,这车还是需要谨慎驾驶。
【1】 绘制一个支持拖动的球 (gif图没录好,就先用静态图吧)

效果图:
没有gif图,就先不贴了,以后录好了再替换上。
关键点分析:
- 绘制图形的方法里,需要缩放和拖动一同处理,即:便宜量和缩放比率的处理。
- 使用三个按钮(放大,还原,缩小)开放缩放功能,

代码 (只粘贴了body段,其他部分用模板就行了):

<body>
    <canvas id="can" width="800" height="500"></canvas>
    <div>>
        <button id="btn_in">放大</button>
        <button id="btn_normal">还原</button>
        <button id="btn_out">缩小</button>
    </div>
    <div>1 不管是否点中红球,都能拖动; 2 包含缩放和拖动</div>
    <div id="posdiv"></div>
    <div>  圆心坐标:
        <div id="centerdiv"></div>
    </div>

    <script type="text/javascript">
        var can = document.getElementById("can");
        var ctx = can.getContext("2d");
        var isDown = false;
        var dx = 0, 
            dy = 0; // 鼠标按下位置的坐标
        var offx = 0, offy = 0; // 拖动的距离,x,y
        var centerx = 50,
            centery = 50; // 圆心坐标

        var cx = 0, cy = 0; // 画布中心点坐标

        // 原始比率(scaler = 1)时,拖动产生的偏移量
        var _x  = 0, _y  = 0; // 这个变量用来计算缩放后的偏移量误差

        var scaler = 1; // 缩放比率

        /**
         * 创建圆滑块:  圆心坐标  x,y
         */
        function createBlock(fished) {
            /**
             * 画布中心点 + (中心点与圆心间距*缩放系数)  + 偏移量 
             */
            var nx = cx + (centerx-cx)*scaler + offx;
            var ny = cy + (centery-cy)*scaler + offy;

            ctx.clearRect(0, 0, can.width, can.height);
            ctx.beginPath();
            ctx.save();
            // ctx.translate(cx, cy);
            ctx.fillStyle = "red";

            console.log("圆心坐标="+centerx+","+centery+"画布中心点="+cx+", "+cy);
            ctx.arc(nx, ny, 30*scaler, 0, Math.PI * 2);
            ctx.fill();
            ctx.restore();
        }

        //鼠标按下,将鼠标按下坐标保存在x,y中  
        can.onmousedown = function(ev) {
            var e = ev || window.event;
            dx = e.clientX;
            dy = e.clientY;
            isDown = true;
            can.onmousemove = function(ev) {
                $("#posdiv").html("鼠标坐标,x="+ev.clientX+", y="+ev.clientY);
                if (isDown) {
                    var e = ev || window.event;
                    var mx = e.clientX;
                    var my = e.clientY;

                    offx = mx - dx;
                    offy = my - dy;

                    createBlock();
                }
            };
            //鼠标移开事件  
            can.onmouseup = function(ev) {
                isDown = false;
                var e = ev || window.event;
                createBlock(true);

                // 重置
                centerx += (e.clientX - dx)/scaler;
                centery += (e.clientY - dy)/scaler;

                offx = 0;
                offy = 0;
                can.onmousemove = null;
                can.onmouseup = null;
            };
        };

        var mouseHandler = function(ev) {
            if (ev.type == "mousewheel") {
                var e = (ev || window.event).originalEvent;
                var deltaY = e.wheelDelta;

                if(deltaY == 120) {
                    $("#btn_in").trigger("click");
                } else if(deltaY == -120) {
                    $("#btn_out").trigger("click");
                }
            }
        };

        $(can).off().on({
            mousewheel : mouseHandler,
        });

        $(function(){
            cx = $("canvas")[0].width / 2;
            cy = $("canvas")[0].height / 2;
            createBlock();
            $("#btn_in").off().on({
                "click": function() {
                    scaler += 0.5;
                    createBlock();

                }
            });

            $("#btn_normal").off().on({
                "click": function() {
                    scaler = 1;
                    _x  = 0, _y  = 0;
                    createBlock();
                }
            });

            $("#btn_out").off().on({
                "click": function() {
                    if (scaler <=1 ){
                        $.toast("alreay smallest, cannot zoom out!");
                        return;
                    }

                    scaler -= 0.5;
                    createBlock();
                }
            });
        })
    </script>

</body>

注意:
1 这个带缩放版本的代码比只能拖动的代码,多做了一些优化,并使用jQuery(因为我是通过jQuery开始使用js的,jQuery比原生js简单方便很多啊):
2 在完成这个demo版本的功能过程中,我也是查询了很多资料,并咨询了同事,所以还要在what 的基础研究how 和 why;
3 注释我觉得很全了,有问题的话,评论里咱们共同探讨。
4 闭包我还用不好,所以很尴尬的是,我没有像同事一样使用闭包封装,定义了一堆丑陋的成员变量。
5 当然是代码啦,点我

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值