用Canvas实现 坐标线 画图 拖拽 移动

主要分三步

1. html页面

2. mikuCanvasAxes.js

3. mikuCanvasPaintAppMain.js

在html页面中直接引入以上两个js即可,就可实现如下功能
1. 点击添加块出现红色的圆形
2. 当鼠标拖拽红色的圆形便会出现x,y轴线随着圆的移动随着他移动
3. 移动图的同时最上方会出现你所移动的坐标数
用Canvas实现 坐标线 画图 拖拽 移动_第1张图片

1.html页面


<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <title>Document</title>
        <style type="text/css">
            canvas{
                background-color: rgb(247, 247, 247);
                margin-top: 10px;
                border: thin solid blue;
            }
        </style>
    </head>
    <body>
         <p id="message"></p>
        <div class="controls">
            网格线<input  id="gridCheckBox" type="checkbox" checked="checked" >
            坐标轴<input  id="axesCheckBox" type="checkbox" checked="checked" >
            <!-- 辅助线<input  id="guideWiresCheckBox" type="checkbox" checked="checked" > -->
            <input type="button" value="清除画布" id="eraseAllButton">
            <input type="button" value="添加块" id="addBlock">
        </div>
        <!--canvas默认大小300*150-->
        <canvas id="canvas" width="800" height="500">
        </canvas>
    </body>
        <!--导入绘制坐标、网格的js文件-->
        <script type = "text/javascript" src ="mikuCanvasAxes.js"></script>
        <!--导入主要绘图js文件-->
        <!--
            全局变量定义
            函数:窗口坐标转换为Canvas坐标、保存\还原当前绘图表面数据、橡皮筋法相关函数、绘制辅助线相关函数、初始化函数
            事件处理:鼠标down,move,up事件、按钮点击事件、单选框变化事件
        -->
        <script type = "text/javascript" src ="mikuCanvasPaintAppMain.js"></script>
</html>

引入js文件第一个: (mikuCanvasAxes.js)

//Classes----------------------------------------------------
function mikuLoc(locX,locY){
    this.x = locX;
    this.y = locY;
}
//Contents---------------------------------------------------
var GRID_STYLE  = "lightgray",
    GRID_LINE_WIDTH = 0.5;
 
var AXES_STYLE  = "#a2a2a2",
    AXES_LINE_WIDTH = 1,
    VERTICAL_TICK_SPACING = 10,
    HORIZONTAL_TIKE_SPACING = 10,
    TICK_WIDTH = 10;
//Function---------------------------------------------------
//绘制网格
//传入参数为:绘图环境,x轴间隔,y轴间隔
function drawGrid(context,stepx,stepy){
    context.save();
    context.strokeStyle = GRID_STYLE;
    //设置线宽为0.5
    context.lineWidth   = GRID_LINE_WIDTH;
    //绘制x轴网格
    //注意:canvas在两个像素的边界处画线
    //由于定位机制,1px的线会变成2px
    //于是要+0.5
    for(var i=stepx+0.5;i<context.canvas.width;i=i+stepx){
        //开启路径
        context.beginPath();
        context.moveTo(i,0);
        context.lineTo(i,context.canvas.height);
        context.stroke();
        }
        //绘制y轴网格
    for(var i=stepy+0.5;i<context.canvas.height;i=i+stepy){
        context.beginPath();
        context.moveTo(0,i);
        context.lineTo(context.canvas.width,i);
        context.stroke();
        }
    context.restore();
};
//Function---------------------------------------------------
//绘制坐标轴
//传入参数为:绘图环境,坐标轴边距
function drawAxes(context,axesMargin){
    //保存样式
    context.save();
    var originLoc = new mikuLoc(axesMargin, context.canvas.height-axesMargin);
    var axesW = context.canvas.width  - (axesMargin*2),
        axesH = context.canvas.height - (axesMargin*2);
    //设置坐标绘图样式绘图样式
    context.strokeStyle   =  AXES_STYLE;
    context.lineWidth =   AXES_LINE_WIDTH;
    //绘制x,y轴
    drawHorizontalAxis();
    drawVerticalAxis();
    drawVerticalAxisTicks();
    drawHorizontalAxisTicks();
    //恢复样式
    context.restore();
    
    //绘制x轴
    function drawHorizontalAxis(){
        context.beginPath();
        context.moveTo(originLoc.x, originLoc.y);
        context.lineTo(originLoc.x + axesW, originLoc.y);
        context.stroke();
    }
    //绘制y轴
    function drawVerticalAxis(){
        context.beginPath();
        context.moveTo(originLoc.x, originLoc.y);
        context.lineTo(originLoc.x, originLoc.y - axesH);
        context.stroke();
    }
    //绘制垂直轴小标标
    function drawVerticalAxisTicks(){
        var deltaX;
        //当前垂直tick的y轴坐标
        var nowTickY =originLoc.y-VERTICAL_TICK_SPACING;
        for(var i=1;i<=(axesH/VERTICAL_TICK_SPACING);i++){
            if(i%5 === 0){
                deltaX=TICK_WIDTH;
            }else {
                deltaX=TICK_WIDTH/2;   
            }
            context.beginPath();
            //移动到当前的tick起点
            context.moveTo(originLoc.x-deltaX,nowTickY);
            context.lineTo(originLoc.x+deltaX,nowTickY);
            context.stroke();
            nowTickY=nowTickY-VERTICAL_TICK_SPACING;
        }
    }
    //绘制水平轴小标标
    function drawHorizontalAxisTicks(){
        var deltaY;
        var nowTickX = originLoc.x+HORIZONTAL_TIKE_SPACING;
         for(var i=1;i<=(axesW/HORIZONTAL_TIKE_SPACING);i++){
            if(i%5 === 0){
                deltaY = TICK_WIDTH;
            }else{
                deltaY = TICK_WIDTH/2;   
            }
            context.beginPath();
            context.moveTo(nowTickX,originLoc.y+deltaY);
            context.lineTo(nowTickX,originLoc.y-deltaY);
            context.stroke();
            nowTickX = nowTickX + HORIZONTAL_TIKE_SPACING;
        }
    }
};

引入js第二个: (mikuCanvasPaintAppMain.js)

//Vars--------------------------------------------------------
        var canvas =document.getElementById("canvas"),
            context =canvas.getContext("2d"),
            //正在绘制的绘图表面变量
            drawingSurfaceImageData,
            //鼠标按下相关对象
            mousedown = {},
            //橡皮筋矩形对象
            rubberbandRect = {},
            //拖动标识变量
            dragging = false;
        
        //控件
        //擦除画布的控制
        var eraseAllButton = document.getElementById("eraseAllButton");
        //坐标轴的控制
        var axesCheckBox = document.getElementById("axesCheckBox");
        //网格线的控制
        var gridCheckBox = document.getElementById("gridCheckBox");
        //辅助线的控制
        var guideWiresCheckBox = document.getElementById("guideWiresCheckBox"); 
        //线条颜色的控制
        var strokeColorSelectBox =document.getElementById("strokeColorSelectBox");
        //线条样式的控制
        var lineTypeSelectBox = document.getElementById("lineTypeSelectBox");
        //线条宽度的控制
        var lineWidthSelectBox = document.getElementById("lineWidthSelectBox");
        //添加块
        var addBlock = document.getElementById('addBlock');
//Functions---------------------------------------------------
          function getLocation(x, y) {
              var bbox = canvas.getBoundingClientRect();
              return {
                  x: (x - bbox.left) * (canvas.width / bbox.width),
                  y: (y - bbox.top) * (canvas.height / bbox.height)

                  /*
                   * 此处不用下面两行是为了防止使用CSS和JS改变了canvas的高宽之后是表面积拉大而实际
                   * 显示像素不变而造成的坐标获取不准的情况
                  x: (x - bbox.left),
                  y: (y - bbox.top)
                  */
              };
          }


        //将窗口坐标转换为Canvas坐标
        //传入参数:窗口坐标(x,y)
        function windowToCanvas(x,y){
            //获取canvas元素的边距对象
            var bbox = canvas.getBoundingClientRect();
            //返回一个坐标对象
            //类似json的一种写法
            return {
                    x : x - bbox.left*(canvas.width/bbox.width),
                    y : y - bbox.top*(canvas.height/bbox.height)
                };
        }
        //保存当前绘图表面数据
        function saveDrawingSurface(){
          //从上下文中获取绘图表面数据
          drawingSurfaceImageData = context.getImageData(0,0,canvas.width,canvas.height);
        }
        //还原当前绘图表面
        function restoreDrawingSurface(){
          //将绘图表面数据还原给上下文
          context.putImageData(drawingSurfaceImageData,0,0);
        }
        //橡皮筋相关函数
        
        //更新橡皮筋矩形+对角线
        //传入参数:坐标对象loc
        function updateRubberband(loc){
            updateRubberbandRectangle(loc);
            drawRubberbandShape(loc);
        }
        //更新橡皮筋矩形
        //传入参数:坐标对象loc
        function updateRubberbandRectangle(loc){
            //获得矩形的宽
            rubberbandRect.width = Math.abs(loc.x - mousedown.x);
            //获得矩形的高
            rubberbandRect.height = Math.abs(loc.y - mousedown.y);
            //获得矩形顶点的位置(left,top)
            //如果鼠标按下的点(起点)在当前点的的左侧
            //这里画一下图就懂了
            if(loc.x > mousedown.x){
                rubberbandRect.left = mousedown.x;
            }else{
                rubberbandRect.left = loc.x;
            }
            if(loc.y > mousedown.y){
                rubberbandRect.top = mousedown.y;
            }else{
                rubberbandRect.top = loc.y;
            }
        }
        //绘制橡皮筋矩形的对角线
        //传入参数:坐标对象loc
        function drawRubberbandShape(loc){
            //获取当前线条类型
            var lineType = lineTypeSelectBox.value;
            //获取当前线条颜色
            var lineColor = strokeColorSelectBox.value;
            //获取当前线条宽度
            var lineWidth = lineWidthSelectBox.value;
            //有改变context画笔属性就要做画笔保护
            context.save();
            context.strokeStyle = lineColor;
            context.lineWidth = lineWidth;
            if(lineType === "solid"){
                //alert("draw");
                //注意重新开始路径
                context.beginPath();
                context.moveTo(mousedown.x,mousedown.y);
                //这里可以更改成画虚线
                context.lineTo(loc.x,loc.y);
                context.stroke();   
            }else if(lineType === "dashed"){
                drawDashedLine(context,mousedown.x,mousedown.y,loc.x,loc.y);
            }
            context.restore();
        }
        
        //绘制辅助用的线-------------------------
        //绘制水平线
        function drawHorizontalLine(y){
            // context.beginPath();
            // context.moveTo(0,y+0.5);
            // context.lineTo(context.canvas.width,y+0.5);
            // context.stroke();

             context.beginPath();
             context.moveTo(0, y);
             context.lineTo(canvas.width, y);
             context.stroke();
             context.closePath();
        }
        //绘制垂直线
        function drawVerticalLine(x){
            // context.beginPath();
            // context.moveTo(x+0.5,0);
            // context.lineTo(x+0.5,context.canvas.height);
            // context.stroke();

             context.beginPath();
             context.moveTo(x, 0);
             context.lineTo(x, canvas.height);
             context.stroke();
             context.closePath();
        }
        //绘制辅助用的线
        function drawGuideWires(x,y){
            //画笔保护
            context.save();
            context.strokeStyle = "red";
            context.lineWidth = 0.5;
            drawHorizontalLine(y);
            drawVerticalLine(x);
            context.restore();
        }
        //初始化函数
        function initialization(){
            //清除画布
            context.clearRect(0,0,canvas.width,canvas.height);
            //绘制网格与坐标的颜色是默认的
            if(axesCheckBox.checked){
               drawAxes(context,40);
            }
            if(gridCheckBox.checked){
               drawGrid(context,10,10);
            }
        }
//Event Hander-----------------------------------------------------
        var timeOutEvent = 0; //区分拖拽和点击的参数
        var r = 30;
        canvas.onmousedown = function(e){
        //    var loc =windowToCanvas(e.clientX,e.clientY);
        //    e.preventDefault();
        //    saveDrawingSurface();
        //    mousedown.x = loc.x;
        //    mousedown.y = loc.y;
            var e = e || event;
            var x = e.layerX;
            var y = e.layerY;
            timeOutEvent = setTimeout("longPress()", 500);
            e.preventDefault();
            drag(x, y, r);
           dragging = true;
        }
        //创建图形
        function createBlock(a, b, r) {
            context.beginPath();
            context.fillStyle = "red";
            context.arc(a, b, r, 0, Math.PI * 2);
            context.fill();
        }
        //拖拽函数
        function drag(x, y, r) {
            console.log(x,y)
            // 按下鼠标判断鼠标位置是否在圆上,当画布上有多个路径时,isPointInPath只能判断最后那一个绘制的路径
            if (context.isPointInPath(x, y)) {
                //路径正确,鼠标移动事件
                canvas.onmousemove = function (ev) {
                    var e = ev || event;
                    ax = e.layerX;
                    ay = e.layerY;
                    console.log(ax, ay)
                    clearTimeout(timeOutEvent);
                    timeOutEvent = 0;
                    //鼠标移动每一帧都清楚画布内容,然后重新画圆
                    context.clearRect(0, 0, canvas.width, canvas.height);
                    

                    // var location = getLocation(ax, ay);
                    var message = document.getElementById("message");
                    message.innerHTML = "x=" + ax + " ,y=" + ay;
                    // context.clearRect(0, 0, canvas.width, canvas.height);
                    initialization();
                    drawHorizontalLine(ay-r);
                    drawVerticalLine(ax-r);
                    createBlock(ax, ay, r);
                };
                //鼠标移开事件
                canvas.onmouseup = function () {
                    canvas.onmousemove = null;
                    canvas.onmouseup = null;
                    clearTimeout(timeOutEvent);
                    // if (timeOutEvent != 0) {
                    //     alert("你这是点击,不是拖拽");
                    // }
                }
            }
        }
        function longPress() {
            timeOutEvent = 0;
        }
/*
        canvas.onmousemove = function(e){
            var loc;
            if(dragging){
                e.preventDefault();
                // loc = windowToCanvas(e.clientX,e.clientY);
                // restoreDrawingSurface();
                // updateRubberband(loc);
            }
            
            if(dragging&&guideWiresCheckBox.checked){
                // drawGuideWires(loc.x,loc.y);
            }
            
            
            // by luyao
            if(guideWiresCheckBox.checked){
                loc = windowToCanvas(e.clientX,e.clientY);
                //restoreDrawingSurface();
                drawGuideWires(loc.x,loc.y);   
            }
            
        }
        canvas.onmouseup = function(e){
            // loc = windowToCanvas(e.clientX,e.clientY);
            // restoreDrawingSurface();
            // updateRubberband(loc);
            dragging = false;
        }
        */
        //点击添加一个块
        addBlock.onclick = function () {
            createBlock(200,200,30)
        }

        //需要擦除的操作需要重新初始化
        eraseAllButton.onclick = function(e){
            context.clearRect(0,0,canvas.width,canvas.height);
            initialization();
            saveDrawingSurface();
        }
        axesCheckBox.onchange = function(e){
            initialization();
        }
        gridCheckBox.onchange = function(e){
            initialization();
        }
//Mian----------------------------------------------
        initialization();

你可能感兴趣的:(Canvas)