Canvas如何画一个线条,画布效果最好添加字体和线条回溯

简介: Canvas如何画一个线条,画布效果最好添加字体和线条回溯

本文源码转载于:

项目文件预览 - CanvasStudy - GitCode

效果展示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>拖拽画直线</title>
</head>
<style>
    body {
        background: #eeeeee;
    }
 
    #controls {
        position: absolute;
        left: 25px;
        top: 25px;
    }
 
    #canvas {
        background: #ffffff;
        cursor: pointer;
        margin-left: 10px;
        margin-top: 10px;
        box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.5);
    }
 
    input[type='button'] {
        background: cornflowerblue;
        cursor: pointer;
        border-radius: 10px;
    }
</style>
<body>
 
<canvas id="canvas" width="600" height="400"></canvas>
 
<div id="controls">
 
    Stroke Color:<select id="strokeStyleSelect" style="margin-right: 20px">
    <option value="red">red</option>
    <option value="green">green</option>
    <option value="blue">blue</option>
    <option value="orange">orange</option>
 
</select>
    Guidewires(坐标辅助线):
    <input type="checkbox" id="guidewireCheckbox" checked style="margin-right: 20px">
    矩形选框
    <input type="checkbox" id="RectangleCheckbox" style="margin-right: 20px">
    <input type="button" id="eraseAllButton" value="清空画布">
</div>
<p>设置笔触颜色,是否添加辅助线,是否使用矩形选框,然后再画布上绘画。如有需要,使用"清除画布"按钮</p>
</body>
<script>
    let canvas = document.getElementById('canvas'),
        context = canvas.getContext('2d'),
        eraseAllButton = document.getElementById('eraseAllButton'),
        guidewireCheckbox = document.getElementById('guidewireCheckbox'),
        strokeStyleSelect = document.getElementById('strokeStyleSelect'),
        RectangleCheckbox = document.getElementById('RectangleCheckbox'),
        drawingSurfaceImageData,
        mousedown = {},
        rubberbandRect = {},
        dragging = false,
        guidewires = guidewireCheckbox.checked,
        rectangle = RectangleCheckbox.checked;
 
    //Function……
 
    /**
     * 画网格
     * @param color
     * @param stepX
     * @param stepY
     */
    function drawGrid(color, stepX, stepY) {
        context.save();
        context.lineWidth = 0.5;
        context.strokeStyle = color;
 
        for (var i = stepX + 0.5; i < canvas.width; i += stepX) {
            context.beginPath();
            context.moveTo(i, 0 + 0.5);
            context.lineTo(i, canvas.height + 0.5)
            context.stroke();
        }
 
        for (var i = stepY + 0.5; i < canvas.height; i += stepY) {
            context.beginPath();
            context.moveTo(0 + 0.5, i);
            context.lineTo(canvas.width, i);
            context.stroke();
        }
        context.restore();
    }
 
    /**
     * 坐标转化为canvas坐标
     * @param x
     * @param y
     */
    function windowToCanvas(x, y) {
        //返回元素的大小以及位置
        var bbox = canvas.getBoundingClientRect();
        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);
    }
 
    //Rubber bands
 
    /**
     * 更新橡皮筋矩形
     * @param loc
     */
    function updateRubberbandRectangle(loc) {
        rubberbandRect.width = Math.abs(loc.x - mousedown.x);
        rubberbandRect.height = Math.abs(loc.y - mousedown.y);
 
        //从左往右拉,和从右往左拉的两种情况。主要是判断左边的位置
        //因为从左往右拉的时候,左边x坐标不变
        //从右往左拉的时候,左边线的x坐标需要跟着鼠标移动
 
        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;
 
        context.save();
        context.beginPath();
        context.rect(rubberbandRect.left, rubberbandRect.top, rubberbandRect.width, rubberbandRect.height);
        context.stroke();
        context.restore();
    }
 
    /**
     * 画可以看得见的线
     * @param loc
     */
    function drawRubberbandShape(loc) {
        context.beginPath();
        context.moveTo(mousedown.x, mousedown.y);
        context.lineTo(loc.x, loc.y);
        context.stroke();
    }
 
    /**
     * 更新橡皮筋
     * @param loc
     */
    function updateRubberband(loc) {
        //如果判断需要画矩形,就执行画矩形方法
        if (rectangle) {
            updateRubberbandRectangle(loc);
        }
        //执行画直线的方法,这里没加if是为了让读者容易理解矩形的绘制方法,因为"draw矩形"是基于"draw直线"的
        drawRubberbandShape(loc);
    }
 
    //Guidewires辅助线
    /**
     * 画水平辅助线,占整个canvas宽度
     * @param y
     */
    function drawHorizontalLine(y) {
        context.beginPath();
        context.moveTo(0, y + 0.5);
        context.lineTo(canvas.width, y + 0.5);
        context.stroke();
    }
 
    /**
     * 画垂直辅助线,占整个canvas高度
     * @param x
     */
    function drawVerticalLine(x) {
        context.beginPath();
        context.moveTo(x + 0.5, 0);
        context.lineTo(x + 0.5, context.canvas.height);
        context.stroke();
    }
 
    /**
     * 画辅助线,并设置属性
     * @param x
     * @param y
     */
    function drawGuidewires(x, y) {
        context.save();
        context.strokeStyle = 'rgba(0,0,230,0.4)';
        context.lineWidth = 0.5;
        drawVerticalLine(x);
        drawHorizontalLine(y);
        context.restore();
    }
 
    //事件
 
    /**
     * 鼠标按下的时候,记录坐标,并设置为拖拽状态
     * @param e
     */
    canvas.onmousedown = function (e) {
        var loc = windowToCanvas(e.clientX, e.clientY);
 
        e.preventDefault();
        saveDrawingSurface();
        mousedown.x = loc.x;
        mousedown.y = loc.y;
        dragging = true;
    };
 
    /**
     * (鼠标按下之后)鼠标移动的时候
     * 判断拖拽中:更新当前连线的位置
     * 判断辅助线显示:添加辅助线
     * @param e
     */
    canvas.onmousemove = function (e) {
        var loc;
        if (dragging) {
            e.preventDefault();
            loc = windowToCanvas(e.clientX, e.clientY);
            restoreDrawingSurface();
            updateRubberband(loc);
            if (guidewires) {
                drawGuidewires(loc.x, loc.y);
            }
        }
 
    };
 
    /**
     * (拖拽完成后)当鼠标松开时,重新获取本点坐标,清除之前的"跟随鼠标移动的线",更新连线,取消拖拽状态
     * @param e
     */
    canvas.onmouseup = function (e) {
        loc = windowToCanvas(e.clientX, e.clientY);
        restoreDrawingSurface();
        updateRubberband(loc);
        dragging = false;
    };
 
    //控制器的事件
 
    /**
     * 清除所有画布图像
     * @param ev
     */
    eraseAllButton.onclick = function (ev) {
        context.clearRect(0, 0, canvas.width, canvas.height);
        drawGrid('lightgray', 10, 10);
        saveDrawingSurface();
    };
 
    strokeStyleSelect.onchange = function (ev) {
        context.strokeStyle = strokeStyleSelect.value;
    };
 
    guidewireCheckbox.onchange = function (ev) {
        guidewires = guidewireCheckbox.checked;
    };
 
    RectangleCheckbox.onchange = function (ev) {
        rectangle = RectangleCheckbox.checked;
    };
 
    //init
 
    context.strokeStyle = strokeStyleSelect.value;
    drawGrid('lightgray', 10, 10);
 
</script>
</html>
相关文章
|
2月前
Qt绘图(线条、椭圆、矩形、图片滚动)
Qt绘图(线条、椭圆、矩形、图片滚动)
43 3
|
1月前
|
前端开发
如何在页面中画一个canvas,然后在居中位置写上蓝色‘Hello Canvas‘,并加上文字描边 * @type {HTMLElement}
如何在页面中画一个canvas,然后在居中位置写上蓝色‘Hello Canvas‘,并加上文字描边 * @type {HTMLElement}
|
1月前
|
前端开发
Canvas如何画一个网格线条
Canvas如何画一个网格线条
|
1月前
|
前端开发
canvas系列教程02——圆、弧线、圆角矩形、曲线(气泡、心形、N叶草)、扇形
canvas系列教程02——圆、弧线、圆角矩形、曲线(气泡、心形、N叶草)、扇形
11 0
CSS3文本居中显示、圆形圆角绘制、立体阴影效果设置实例演示
CSS3文本居中显示、圆形圆角绘制、立体阴影效果设置实例演示
114 0
|
C# 图形学
C#之深入理解GDI+绘制圆弧及圆角矩形等比缩放的绘制
GDI+中对于圆弧的绘制,是以给定的长方形(Rectangle`结构)为边界绘制的椭圆的一部分形成的圆弧。绘制的圆弧的中心为长方形内切椭圆的圆心(如果是正方形,则正方形的...
535 0
C#之深入理解GDI+绘制圆弧及圆角矩形等比缩放的绘制
|
前端开发
基于canvas绘制边框环绕进度条
基于canvas绘制边框环绕进度条
222 0
基于canvas绘制边框环绕进度条
|
前端开发 JavaScript
canvas-渐变文字
html要求: body这里的onload一定要写,在这个处理模式下,是在body这里执行加载页面完成后加载canvas的命令。有的写在了js中的window.onload=function(){},这里就要换一种写法了。
849 0