跳到主要内容

Canvas 贴纸——使用 JavaScript 为图像添加可拖放贴纸

在图像上放置星形、心形、徽章和箭头等贴纸。单击以添加,拖动以移动,使用控制柄调整大小和旋转。将结果导出为 PNG。

操作说明: 单击贴纸按钮以添加贴纸。单击贴纸以选择它并对其进行变换。单击图像以取消选择。

import Konva from 'konva';

var width = window.innerWidth;
var height = window.innerHeight;

var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});

var layer = new Konva.Layer();
stage.add(layer);

var container = document.getElementById('container');

var controls = document.createElement('div');
controls.style.cssText = 'display:flex;gap:8px;margin-bottom:8px;flex-wrap:wrap;align-items:center;';

var stickerTypes = [
{ name: 'Star', emoji: '⭐' },
{ name: 'Heart', emoji: '❤️' },
{ name: 'Badge', emoji: '🔴' },
{ name: 'Arrow', emoji: '➡️' },
];

stickerTypes.forEach(function(s) {
var btn = document.createElement('button');
btn.textContent = s.emoji + ' ' + s.name;
btn.style.cssText = 'padding:6px 12px;cursor:pointer;border:1px solid #ddd;border-radius:4px;background:#f8f9fa;font-size:13px;';
btn.onclick = function() { addSticker(s.name); };
controls.appendChild(btn);
});

var exportBtn = document.createElement('button');
exportBtn.textContent = 'Export PNG';
exportBtn.style.cssText = 'padding:6px 12px;cursor:pointer;border:none;border-radius:4px;background:#333;color:white;font-size:13px;font-weight:600;';
exportBtn.onclick = function() {
transformer.nodes([]);
var link = document.createElement('a');
link.href = stage.toDataURL({ pixelRatio: 2 });
link.download = 'sticker-canvas.png';
link.click();
};
controls.appendChild(exportBtn);
container.parentNode.insertBefore(controls, container);

var imageObj = new Image();
imageObj.onload = function() {
layer.add(new Konva.Image({ image: imageObj, width: width, height: height }));
layer.add(transformer);
};
imageObj.src = 'https://konvajs.org/assets/landscape.jpg';

var transformer = new Konva.Transformer();

function addSticker(type) {
var shape;
var x = 100 + Math.random() * (width - 200);
var y = 80 + Math.random() * (height - 160);
if (type === 'Star') {
shape = new Konva.Star({ x: x, y: y, numPoints: 5, innerRadius: 15, outerRadius: 35, fill: '#FFD700', stroke: '#FFA500', strokeWidth: 2, draggable: true });
} else if (type === 'Heart') {
shape = new Konva.Path({ x: x, y: y, data: 'M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z', scaleX: 2, scaleY: 2, fill: '#FF69B4', draggable: true });
} else if (type === 'Badge') {
shape = new Konva.Circle({ x: x, y: y, radius: 25, fill: '#FF4444', stroke: '#fff', strokeWidth: 3, draggable: true });
} else if (type === 'Arrow') {
shape = new Konva.Arrow({ x: x, y: y, points: [0, 0, 60, 0], fill: '#20C997', stroke: '#20C997', strokeWidth: 3, pointerLength: 12, pointerWidth: 12, draggable: true });
}
if (shape) {
layer.add(shape);
shape.moveToTop();
transformer.moveToTop();
transformer.nodes([shape]);
}
}

stage.on('click tap', function(e) {
if (e.target === stage || e.target.getClassName() === 'Image') {
transformer.nodes([]);
return;
}
if (e.target.getParent() && e.target.getParent().getClassName() === 'Transformer') return;
transformer.nodes([e.target]);
});