如何使用 Konva 在画布上预览大型舞台?

需要生成小型画布预览吗?

生成小型预览的方法有很多。Konva 并未提供自动生成预览的方法。但我们可以使用 Konva 方法手动生成预览区域。

我们将展示两种选项 - 克隆和使用图像。在大型应用中,从应用的状态生成预览会更好。

从主舞台克隆节点。

我们可以直接克隆舞台或图层,并根据主画布区域的状态更新其内部节点。

同时,简化预览中的形状是有意义的。例如,隐藏文本,移除轮廓和阴影等。

说明:尝试拖动一个圆形。看看预览是如何更新的。双击以添加新形状。

Stage_Preview_Clone.htmlview raw
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@9.3.18/konva.min.js"></script>
<meta charset="utf-8" />
<title>Konva Canvas Stage Preview Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;
}

#preview {
position: absolute;
top: 2px;
right: 2px;
border: 1px solid grey;
background-color: lightgrey;
}
</style>
</head>

<body>
<div id="container"></div>
<div id="preview"></div>
<script>
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
});

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

// generate random shapes
for (var i = 0; i < 10; i++) {
const shape = new Konva.Circle({
x: Math.random() * stage.width(),
y: Math.random() * stage.height(),
radius: Math.random() * 30 + 5,
fill: Konva.Util.getRandomColor(),
draggable: true,
// each shape MUSH have uniq name
// so we can easily update the preview clone by name
name: 'shape-' + i,
});
layer.add(shape);
}

// create smaller preview stage
const previewStage = new Konva.Stage({
container: 'preview',
width: window.innerWidth / 4,
height: window.innerHeight / 4,
scaleX: 1 / 4,
scaleY: 1 / 4,
});

// clone original layer, and disable all events on it
// we will use "let" here, because we can redefine layer later
let previewLayer = layer.clone({ listening: false });
previewStage.add(previewLayer);

function updatePreview() {
// we just need to update ALL nodes in the preview
layer.children.forEach((shape) => {
// find cloned node
const clone = previewLayer.findOne('.' + shape.name());
// update its position from the original
clone.position(shape.position());
});
}

stage.on('dragmove', updatePreview);

// add new shapes on double click or double tap
stage.on('dblclick dbltap', () => {
const shape = new Konva.Circle({
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y,
radius: Math.random() * 30 + 5,
fill: Konva.Util.getRandomColor(),
draggable: true,
// each shape MUSH have uniq name
// so we can easily update the preview clone by name
name: 'shape-' + layer.children.length,
});
layer.add(shape);

// remove all layer
previewLayer.destroy();
// generate new one
previewLayer = layer.clone({ listening: false });
previewStage.add(previewLayer);
});
</script>
</body>
</html>

使用图像预览

或者我们可以将舞台导出为图像并将其用作预览。

出于性能原因,我们并不在每个 dragmove 事件中更新预览。

Stage_Preview_Image.htmlview raw
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@9.3.18/konva.min.js"></script>
<meta charset="utf-8" />
<title>Konva Canvas Stage Preview Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;
}

#preview {
position: absolute;
top: 2px;
right: 2px;
border: 1px solid grey;
background-color: lightgrey;
}
</style>
</head>

<body>
<div id="container"></div>
<img id="preview" />
<script>
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
});

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

// generate random shapes
for (var i = 0; i < 10; i++) {
const shape = new Konva.Circle({
x: Math.random() * stage.width(),
y: Math.random() * stage.height(),
radius: Math.random() * 30 + 5,
fill: Konva.Util.getRandomColor(),
draggable: true,
// each shape MUSH have uniq name
// so we can easily update the preview clone by name
name: 'shape-' + i,
});
layer.add(shape);
}

function updatePreview() {
const scale = 1 / 4;
// use pixelRatio to generate smaller preview
const url = stage.toDataURL({ pixelRatio: scale });
document.getElementById('preview').src = url;
}

// update preview only on dragend for performance
stage.on('dragend', updatePreview);

// add new shapes on double click or double tap
stage.on('dblclick dbltap', () => {
const shape = new Konva.Circle({
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y,
radius: Math.random() * 30 + 5,
fill: Konva.Util.getRandomColor(),
draggable: true,
// each shape MUSH have uniq name
// so we can easily update the preview clone by name
name: 'shape-' + layer.children.length,
});
layer.add(shape);

updatePreview();
});

// show initial preview
updatePreview();
</script>
</body>
</html>