konvajs制作畫板功能 類似QQ截圖 可拖動(dòng)
截圖演示
畫板palette.gif
一、變量申明
let draw=[], // 繪制的圖形數(shù)組
graphNow=null, // 當(dāng)前圖形
flag=null, // 激活繪制-鉛筆 pencil:鉛筆 ellipse:橢圓 rect:矩形 rectH:矩形-空心
drawing=false, // 繪制中
graphColor='red', // 默認(rèn)顏色
pointStart=[]; // 初始坐標(biāo)
二奖磁、獲得Konva對(duì)象
// 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) {
// 如果點(diǎn)擊空白處 移除圖形選擇框
// console.log(e);
if (e.target === stage) {
stageMousedown(flag, e);
// 移除圖形選擇框
stage.find('Transformer').destroy();
layer.draw();
return;
}
// 如果沒有匹配到就終止往下執(zhí)行
if (!e.target.hasName('line') && !e.target.hasName('ellipse') && !e.target.hasName('rect') && !e.target.hasName('circle')) {
return;
}
// 移除圖形選擇框
stage.find('Transformer').destroy();
// 當(dāng)前點(diǎn)擊的對(duì)象賦值給graphNow
graphNow=e.target;
// 創(chuàng)建圖形選框事件
const tr = new Konva.Transformer({
borderStroke: '#000', // 虛線顏色
borderStrokeWidth: 1, //虛線大小
borderDash: [5], // 虛線間距
keepRatio: false // 不等比縮放
});
layer.add(tr);
tr.attachTo(e.target);
layer.draw();
});
// 鼠標(biāo)移動(dòng)
stage.on('mousemove', function (e) {
if (graphNow && flag && drawing) {
stageMousemove(flag, e);
}
});
// 鼠標(biāo)放開
stage.on('mouseup', function () {
drawing=false;
if (flag === 'text') flag=null;
});
三、繪制
1.鉛筆
// 鉛筆
// @param points 點(diǎn)數(shù)組
// @param stroke 顏色
// @param strokeWidth 線粗細(xì)
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坐標(biāo)
// @param y y坐標(biāo)
// @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坐標(biāo)
* @param y y坐標(biāo)
* @param w 寬
* @param h 高
* @param c 顏色
* @param sw 該值大于0-表示空心矩形(描邊寬),等于0-表示實(shí)心矩形
*/
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坐標(biāo)
* @param y y坐標(biāo)
* @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() {
// 在畫布上創(chuàng)建具有絕對(duì)位置的textarea
// 首先,我們需要為textarea找到位置
// 首先,讓我們找到文本節(jié)點(diǎn)相對(duì)于舞臺(tái)的位置:
let textPosition = this.getAbsolutePosition();
// 然后讓我們?cè)陧?yè)面上找到stage容器的位置
let stageBox = stage.container().getBoundingClientRect();
// 因此textarea的位置將是上面位置的和
let areaPosition = {
x: stageBox.left + textPosition.x,
y: stageBox.top + textPosition.y
};
// 創(chuàng)建textarea并設(shè)置它的樣式
let textarea = document.createElement('textarea');
document.body.appendChild(textarea);
let T=this.text();
if (T === '雙擊編輯文字') {
textarea.value = '';
textarea.setAttribute('placeholder','請(qǐng)輸入文字')
} 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)
}
};
// 鼠標(biāo)失去焦點(diǎn)
let blur=() => {
textarea.removeEventListener('keydown', keydown);
confirm(textarea.value);
};
textarea.addEventListener('keydown', keydown);
textarea.addEventListener('blur', blur);
});
}
5.鼠標(biāo)按下
/**
* stage鼠標(biāo)按下
* @param flag 是否可繪制
* @param ev 傳入的event對(duì)象
*/
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.鼠標(biāo)移動(dòng)
/**
* stage鼠標(biāo)移動(dòng)
* @param flag 是否可繪制
* @param ev 傳入的event對(duì)象
*/
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('請(qǐng)選擇圖形')
}
}