canvas库konvajs制作画板功能 类似QQ截图 可拖动

konvajs制作画板功能 类似QQ截图 可拖动

demo演示
gif地址

截图演示


画板palette.gif

一、变量申明

let draw=[], // 绘制的图形数组
    graphNow=null, // 当前图形
    flag=null, // 激活绘制-铅笔 pencil:铅笔 ellipse:椭圆 rect:矩形 rectH:矩形-空心
    drawing=false, // 绘制中
    graphColor='red', // 默认颜色
    pointStart=[]; // 初始坐标

二、获得Konva对象

// 1 create stage
const stage=new Konva.Stage({
    container: 'container',
    width: 1200,
    height: 800
});

// 2 create layer
const layer=new Konva.Layer();
stage.add(layer);

// 3 create our shape

// 移除改变大小事件
stage.on('mousedown', function(e) {
    // 如果点击空白处 移除图形选择框
    // console.log(e);

    if (e.target === stage) {
        stageMousedown(flag, e);

        // 移除图形选择框
        stage.find('Transformer').destroy();
        layer.draw();
        return;
    }
    // 如果没有匹配到就终止往下执行
    if (!e.target.hasName('line') && !e.target.hasName('ellipse') && !e.target.hasName('rect') && !e.target.hasName('circle')) {
        return;
    }
    // 移除图形选择框
    stage.find('Transformer').destroy();

    // 当前点击的对象赋值给graphNow
    graphNow=e.target;
    // 创建图形选框事件
    const tr = new Konva.Transformer({
        borderStroke: '#000', // 虚线颜色
        borderStrokeWidth: 1, //虚线大小
        borderDash: [5], // 虚线间距
        keepRatio: false // 不等比缩放
    });
    layer.add(tr);
    tr.attachTo(e.target);
    layer.draw();
});

// 鼠标移动
    stage.on('mousemove', function (e) {
        if (graphNow && flag && drawing) {
            stageMousemove(flag, e);
        }
    });

    // 鼠标放开
    stage.on('mouseup', function () {
        drawing=false;
        if (flag === 'text') flag=null;
    });

三、绘制

1.铅笔

// 铅笔
// @param points 点数组
// @param stroke 颜色
// @param strokeWidth 线粗细

function drawPencil(points, stroke, strokeWidth) {
    const line = new Konva.Line({
        name: 'line',
        points: points,
        stroke: stroke,
        strokeWidth: strokeWidth,
        lineCap: 'round',
        lineJoin: 'round',
        tension: 0.5,
        draggable: true
    });
    graphNow=line;
    layer.add(line);
    layer.draw();

    line.on('mouseenter', function() {
        stage.container().style.cursor = 'move';
    });

    line.on('mouseleave', function() {
        stage.container().style.cursor = 'default';
    });

    line.on('dblclick', function() {
        // 双击删除自己
        this.remove();
        stage.find('Transformer').destroy();
        layer.draw();
    });
}

2.椭圆

 // 椭圆
 // @param x x坐标
 // @param y y坐标
 // @param rx x半径
 // @param ry y半径
 // @param stroke 描边颜色
 // @param strokeWidth 描边大小
 
function drawEllipse(x, y, rx, ry, stroke, strokeWidth) {
    const ellipse=new Konva.Ellipse({
        name: 'ellipse',
        x: x,
        y: y,
        radiusX: rx,
        radiusY: ry,
        stroke: stroke,
        strokeWidth: strokeWidth,
        draggable: true
    });
    graphNow=ellipse;
    layer.add(ellipse);
    layer.draw();

    ellipse.on('mouseenter', function() {
        stage.container().style.cursor = 'move';
    });

    ellipse.on('mouseleave', function() {
        stage.container().style.cursor = 'default';
    });

    ellipse.on('dblclick', function() {
        // 双击删除自己
        this.remove();
        stage.find('Transformer').destroy();
        layer.draw();
    });
}

3.绘制矩形

/**
 * 矩形
 * @param x x坐标
 * @param y y坐标
 * @param w 宽
 * @param h 高
 * @param c 颜色
 * @param sw 该值大于0-表示空心矩形(描边宽),等于0-表示实心矩形
 */
function drawRect(x, y, w, h, c, sw) {
    const rect = new Konva.Rect({
        name: 'rect',
        x: x,
        y: y,
        width: w,
        height: h,
        fill: sw===0?c:null,
        stroke: sw>0?c:null,
        strokeWidth: sw,
        opacity: sw===0?0.5:1,
        draggable: true
    });
    graphNow=rect;
    layer.add(rect);
    layer.draw();

    rect.on('mouseenter', function() {
        stage.container().style.cursor = 'move';
    });

    rect.on('mouseleave', function() {
        stage.container().style.cursor = 'default';
    });

    rect.on('dblclick', function() {
        // 双击删除自己
        this.remove();
        stage.find('Transformer').destroy();
        layer.draw();
    });
}

4.文字

/**
 * 输入文字
 * @param x x坐标
 * @param y y坐标
 * @param fill 文字颜色
 * @param fs 文字大小
 */
function drawText(x, y, fill, fs) {
    var text = new Konva.Text({
        text: '双击编辑文字',
        x: x,
        y: y,
        fill: fill,
        fontSize: fs,
        width: 300,
        draggable: true
    });
    graphNow=text;
    layer.add(text);
    layer.draw();

    text.on('mouseenter', function() {
        stage.container().style.cursor = 'move';
    });

    text.on('mouseleave', function() {
        stage.container().style.cursor = 'default';
    });

    text.on('dblclick', function() {
        // 在画布上创建具有绝对位置的textarea

        // 首先,我们需要为textarea找到位置

        // 首先,让我们找到文本节点相对于舞台的位置:
        let textPosition = this.getAbsolutePosition();

        // 然后让我们在页面上找到stage容器的位置
        let stageBox = stage.container().getBoundingClientRect();

        // 因此textarea的位置将是上面位置的和
        let areaPosition = {
            x: stageBox.left + textPosition.x,
            y: stageBox.top + textPosition.y
        };

        // 创建textarea并设置它的样式
        let textarea = document.createElement('textarea');
        document.body.appendChild(textarea);

        let T=this.text();
        if (T === '双击编辑文字') {
            textarea.value = '';
            textarea.setAttribute('placeholder','请输入文字')
        } else {
            textarea.value = T;
        }

        textarea.style.position = 'absolute';
        textarea.style.top = areaPosition.y + 'px';
        textarea.style.left = areaPosition.x + 'px';
        textarea.style.background = 'none';
        textarea.style.border = '1px dashed #000';
        textarea.style.outline = 'none';
        textarea.style.color = this.fill();
        textarea.style.width = this.width();

        textarea.focus();

        this.setAttr('text', '');
        layer.draw();

        // 确定输入的文字
        let confirm=(val) => {
            this.text(val?val:'双击编辑文字');
            layer.draw();
            // 隐藏在输入
            if (textarea) document.body.removeChild(textarea);
        };
        // 回车键
        let keydown=(e) => {
            if (e.keyCode === 13) {
                textarea.removeEventListener('blur', blur);
                confirm(textarea.value)
            }
        };
        // 鼠标失去焦点
        let blur=() => {
            textarea.removeEventListener('keydown', keydown);
            confirm(textarea.value);
        };

        textarea.addEventListener('keydown', keydown);
        textarea.addEventListener('blur', blur);
    });
}

5.鼠标按下

/**
 * stage鼠标按下
 * @param flag 是否可绘制
 * @param ev 传入的event对象
 */
function stageMousedown(flag, ev) {
    if (flag) {
        let x=ev.evt.offsetX, y=ev.evt.offsetY;
        pointStart=[x, y];

        switch (flag) {
            case 'pencil':
                drawPencil(pointStart, graphColor, 2);
                break;
            case 'ellipse':
                // 椭圆
                drawEllipse(x, y, 0, 0, graphColor, 2);
                break;
            case 'rect':
                drawRect(x, y, 0, 0, graphColor, 0);
                break;
            case 'rectH':
                drawRect(x, y, 0, 0, graphColor, 2);
                break;
            case 'text':
                drawText(x, y, graphColor, 16);
                break;
            default:
                break;
        }
        drawing=true;
    }
}

6.鼠标移动

/**
 * stage鼠标移动
 * @param flag 是否可绘制
 * @param ev 传入的event对象
 */
function stageMousemove(flag, ev) {
    switch (flag) {
        case 'pencil':
            // 铅笔
            pointStart.push(ev.evt.offsetX, ev.evt.offsetY);
            graphNow.setAttrs({
                points: pointStart
            });
            break;
        case 'ellipse':
            // 椭圆
            graphNow.setAttrs({
                radiusX: Math.abs(ev.evt.offsetX-pointStart[0]),
                radiusY: Math.abs(ev.evt.offsetY-pointStart[1])
            });
            break;
        case 'rect':
        case 'rectH':
            graphNow.setAttrs({
                width: ev.evt.offsetX-pointStart[0],
                height: ev.evt.offsetY-pointStart[1]
            });
            break;
        default:
            break;
    }
    layer.draw();
}

7.选择颜色

// 选择颜色
function selectColorFn(t) {
    graphColor=t.value;
}

8.删除

// 移除图形
function removeFn() {
    if (graphNow) {
        graphNow.remove();
        stage.find('Transformer').destroy();
        layer.draw();
        graphNow=null;
    } else {
        alert('请选择图形')
    }
}

你可能感兴趣的:(canvas库konvajs制作画板功能 类似QQ截图 可拖动)