mirror of
https://github.com/konvajs/konva.git
synced 2025-04-05 20:48:28 +08:00
experimental Offscreen canvas support
This commit is contained in:
parent
b7b50f22d8
commit
8f18165273
@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
* Add `rotationSnapTolerance` property to `Konva.Transformer`.
|
* Add `rotationSnapTolerance` property to `Konva.Transformer`.
|
||||||
* Add `getActiveAnchor()` method to `Konva.Transformer`
|
* Add `getActiveAnchor()` method to `Konva.Transformer`
|
||||||
* Fix hit for non-closed `Konva.Path`
|
* Fix hit for non-closed `Konva.Path`
|
||||||
|
* Some fixes for experimental Offscreen canvas support inside a worker
|
||||||
|
|
||||||
## 4.1.6 - 2020-02-25
|
## 4.1.6 - 2020-02-25
|
||||||
|
|
||||||
|
@ -115,8 +115,8 @@ export class Canvas {
|
|||||||
return this.height;
|
return this.height;
|
||||||
}
|
}
|
||||||
setSize(width, height) {
|
setSize(width, height) {
|
||||||
this.setWidth(width);
|
this.setWidth(width || 0);
|
||||||
this.setHeight(height);
|
this.setHeight(height || 0);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* to data url
|
* to data url
|
||||||
|
61
src/Stage.ts
61
src/Stage.ts
@ -164,6 +164,9 @@ export class Stage extends Container<BaseLayer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_checkVisibility() {
|
_checkVisibility() {
|
||||||
|
if (!this.content) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const style = this.visible() ? '' : 'none';
|
const style = this.visible() ? '' : 'none';
|
||||||
this.content.style.display = style;
|
this.content.style.display = style;
|
||||||
}
|
}
|
||||||
@ -339,28 +342,22 @@ export class Stage extends Container<BaseLayer> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
_resizeDOM() {
|
_resizeDOM() {
|
||||||
|
var width = this.width();
|
||||||
|
var height = this.height();
|
||||||
if (this.content) {
|
if (this.content) {
|
||||||
var width = this.width(),
|
|
||||||
height = this.height(),
|
|
||||||
layers = this.getChildren(),
|
|
||||||
len = layers.length,
|
|
||||||
n,
|
|
||||||
layer;
|
|
||||||
|
|
||||||
// set content dimensions
|
// set content dimensions
|
||||||
this.content.style.width = width + PX;
|
this.content.style.width = width + PX;
|
||||||
this.content.style.height = height + PX;
|
this.content.style.height = height + PX;
|
||||||
|
|
||||||
this.bufferCanvas.setSize(width, height);
|
|
||||||
this.bufferHitCanvas.setSize(width, height);
|
|
||||||
|
|
||||||
// set layer dimensions
|
|
||||||
for (n = 0; n < len; n++) {
|
|
||||||
layer = layers[n];
|
|
||||||
layer.setSize({ width, height });
|
|
||||||
layer.draw();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.bufferCanvas.setSize(width, height);
|
||||||
|
this.bufferHitCanvas.setSize(width, height);
|
||||||
|
|
||||||
|
// set layer dimensions
|
||||||
|
this.children.each(layer => {
|
||||||
|
layer.setSize({ width, height });
|
||||||
|
layer.draw();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
add(layer) {
|
add(layer) {
|
||||||
if (arguments.length > 1) {
|
if (arguments.length > 1) {
|
||||||
@ -997,26 +994,36 @@ export class Stage extends Container<BaseLayer> {
|
|||||||
this.setPointersPositions(evt);
|
this.setPointersPositions(evt);
|
||||||
}
|
}
|
||||||
_getContentPosition() {
|
_getContentPosition() {
|
||||||
var rect = this.content.getBoundingClientRect
|
if (!this.content || !this.content.getBoundingClientRect) {
|
||||||
? this.content.getBoundingClientRect()
|
return {
|
||||||
: { top: 0, left: 0, width: 1000, height: 1000 };
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
scaleX: 1,
|
||||||
|
scaleY: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var rect = this.content.getBoundingClientRect();
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
top: rect.top,
|
top: rect.top,
|
||||||
left: rect.left,
|
left: rect.left,
|
||||||
// sometimes clientWidth can be equals to 0
|
// sometimes clientWidth can be equals to 0
|
||||||
// i saw it in react-konva test, looks like it is because of hidden testing element
|
// i saw it in react-konva test, looks like it is because of hidden testing element
|
||||||
scaleX: rect.width / this.content.clientWidth || 1,
|
scaleX: rect.width / this.content.clientWidth || 1,
|
||||||
scaleY: rect.height / this.content.clientHeight || 1,
|
scaleY: rect.height / this.content.clientHeight || 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_buildDOM() {
|
_buildDOM() {
|
||||||
// the buffer canvas pixel ratio must be 1 because it is used as an
|
this.bufferCanvas = new SceneCanvas({
|
||||||
// intermediate canvas before copying the result onto a scene canvas.
|
width: this.width(),
|
||||||
// not setting it to 1 will result in an over compensation
|
height: this.height()
|
||||||
this.bufferCanvas = new SceneCanvas();
|
});
|
||||||
this.bufferHitCanvas = new HitCanvas({ pixelRatio: 1 });
|
this.bufferHitCanvas = new HitCanvas({
|
||||||
|
pixelRatio: 1,
|
||||||
|
width: this.width(),
|
||||||
|
height: this.height()
|
||||||
|
});
|
||||||
|
|
||||||
if (!Konva.isBrowser) {
|
if (!Konva.isBrowser) {
|
||||||
return;
|
return;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Konva Canvas Scrolling Demo</title>
|
<title>Konva Offscreen Canvas Demo</title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -13,15 +13,46 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<canvas id="canvas"></div>
|
<canvas id="canvas"></canvas>
|
||||||
<script>
|
<script>
|
||||||
var htmlCanvas = document.getElementById("canvas");
|
var htmlCanvas = document.getElementById('canvas');
|
||||||
|
htmlCanvas.width = window.innerWidth;
|
||||||
|
htmlCanvas.height = window.innerHeight;
|
||||||
var offscreen = htmlCanvas.transferControlToOffscreen();
|
var offscreen = htmlCanvas.transferControlToOffscreen();
|
||||||
|
|
||||||
var w = new Worker('./worker.js');
|
var w = new Worker('./worker.js');
|
||||||
w.onmessage = function(event) {
|
w.postMessage({ canvas: offscreen }, [offscreen]);
|
||||||
document.getElementById('result').innerHTML = event.data;
|
|
||||||
};
|
var EVENTS = [
|
||||||
|
'mouseenter',
|
||||||
|
'mousedown',
|
||||||
|
'mousemove',
|
||||||
|
'mouseup',
|
||||||
|
'mouseout',
|
||||||
|
'touchstart',
|
||||||
|
'touchmove',
|
||||||
|
'touchend',
|
||||||
|
'mouseover',
|
||||||
|
'wheel',
|
||||||
|
'contextmenu',
|
||||||
|
'pointerdown',
|
||||||
|
'pointermove',
|
||||||
|
'pointerup',
|
||||||
|
'pointercancel',
|
||||||
|
'lostpointercapture'
|
||||||
|
];
|
||||||
|
|
||||||
|
EVENTS.forEach(eventName => {
|
||||||
|
htmlCanvas.addEventListener(eventName, e => {
|
||||||
|
w.postMessage({
|
||||||
|
eventName,
|
||||||
|
event: {
|
||||||
|
clientX: e.clientX,
|
||||||
|
clientY: e.clientY
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
195
test/worker.js
195
test/worker.js
@ -1,33 +1,194 @@
|
|||||||
// Can we start Konva inside worker?
|
|
||||||
|
|
||||||
importScripts('../../konva.js');
|
importScripts('../../konva.js');
|
||||||
console.log(Konva);
|
|
||||||
|
|
||||||
Konva.Util.createCanvasElement = () => {
|
Konva.Util.createCanvasElement = () => {
|
||||||
const canvas = new OffscreenCanvas(100, 100);
|
const canvas = new OffscreenCanvas(1, 1);
|
||||||
canvas.style = {};
|
canvas.style = {};
|
||||||
return canvas;
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
Konva.Canvas.prototype.setSize = function(width, height) {
|
|
||||||
this.setWidth(width || 1);
|
|
||||||
this.setHeight(height || 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
Konva.Stage.prototype._checkVisibility = function() {};
|
|
||||||
|
|
||||||
var stage = new Konva.Stage({
|
var stage = new Konva.Stage({
|
||||||
width: 100,
|
width: 200,
|
||||||
height: 100
|
height: 200
|
||||||
});
|
});
|
||||||
|
|
||||||
var layer = new Konva.Layer();
|
var layer = new Konva.Layer();
|
||||||
stage.add(layer);
|
stage.add(layer);
|
||||||
|
|
||||||
var shape = new Konva.Circle({
|
var topGroup = new Konva.Group();
|
||||||
|
layer.add(topGroup);
|
||||||
|
|
||||||
|
var counter = new Konva.Text({
|
||||||
|
x: 5,
|
||||||
|
y: 35
|
||||||
|
});
|
||||||
|
topGroup.add(counter);
|
||||||
|
|
||||||
|
var button = new Konva.Label({
|
||||||
|
x: 5,
|
||||||
|
y: 5,
|
||||||
|
opacity: 0.75
|
||||||
|
});
|
||||||
|
topGroup.add(button);
|
||||||
|
|
||||||
|
button.add(
|
||||||
|
new Konva.Tag({
|
||||||
|
fill: 'black'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
button.add(
|
||||||
|
new Konva.Text({
|
||||||
|
text: 'Push me to add bunnies',
|
||||||
|
fontFamily: 'Calibri',
|
||||||
|
fontSize: 18,
|
||||||
|
padding: 5,
|
||||||
|
fill: 'white'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
var circle = new Konva.Circle({
|
||||||
x: stage.width() / 2,
|
x: stage.width() / 2,
|
||||||
y: stage.height() / 2,
|
y: stage.height() / 2,
|
||||||
radius: 50,
|
radius: 20,
|
||||||
fill: 'red'
|
fill: 'red',
|
||||||
|
draggable: true
|
||||||
});
|
});
|
||||||
layer.add(shape);
|
topGroup.add(circle);
|
||||||
|
layer.draw();
|
||||||
|
|
||||||
|
onmessage = function(evt) {
|
||||||
|
if (evt.data.canvas) {
|
||||||
|
var canvas = evt.data.canvas;
|
||||||
|
stage.setSize({
|
||||||
|
width: canvas.width,
|
||||||
|
height: canvas.height
|
||||||
|
});
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
setInterval(() => {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.drawImage(layer.getCanvas()._canvas, 0, 0);
|
||||||
|
}, 16);
|
||||||
|
}
|
||||||
|
if (evt.data.eventName === 'mouseup') {
|
||||||
|
Konva.DD._endDragBefore(evt.data.event);
|
||||||
|
}
|
||||||
|
if (evt.data.eventName === 'touchend') {
|
||||||
|
Konva.DD._endDragBefore(evt.data.event);
|
||||||
|
}
|
||||||
|
if (evt.data.eventName === 'mousemove') {
|
||||||
|
Konva.DD._drag(evt.data.event);
|
||||||
|
}
|
||||||
|
if (evt.data.eventName === 'touchmove') {
|
||||||
|
Konva.DD._drag(evt.data.event);
|
||||||
|
}
|
||||||
|
if (evt.data.eventName === 'mouseup') {
|
||||||
|
Konva.DD._endDragAfter(evt.data.event);
|
||||||
|
}
|
||||||
|
if (evt.data.eventName === 'touchend') {
|
||||||
|
Konva.DD._endDragAfter(evt.data.event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.data.eventName) {
|
||||||
|
stage['_' + evt.data.eventName](evt.data.event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function requestAnimationFrame(cb) {
|
||||||
|
setTimeout(cb, 16);
|
||||||
|
}
|
||||||
|
async function runBunnies() {
|
||||||
|
var bunnys = [];
|
||||||
|
var gravity = 0.75;
|
||||||
|
|
||||||
|
var startBunnyCount = 100;
|
||||||
|
var isAdding = false;
|
||||||
|
var count = 0;
|
||||||
|
var amount = 10;
|
||||||
|
const imgBlob = await fetch('./assets/bunny.png').then(r => r.blob());
|
||||||
|
const img = await createImageBitmap(imgBlob);
|
||||||
|
|
||||||
|
button.on('mousedown', function() {
|
||||||
|
isAdding = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
button.on('mouseup', function() {
|
||||||
|
isAdding = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var i = 0; i < startBunnyCount; i++) {
|
||||||
|
var bunny = new Konva.Image({
|
||||||
|
image: img,
|
||||||
|
transformsEnabled: 'position',
|
||||||
|
hitGraphEnabled: false,
|
||||||
|
x: 10,
|
||||||
|
y: 10,
|
||||||
|
listening: false
|
||||||
|
});
|
||||||
|
|
||||||
|
bunny.speedX = Math.random() * 10;
|
||||||
|
bunny.speedY = Math.random() * 10 - 5;
|
||||||
|
|
||||||
|
bunnys.push(bunny);
|
||||||
|
counter.text('Bunnies number: ' + bunnys.length);
|
||||||
|
layer.add(bunny);
|
||||||
|
}
|
||||||
|
topGroup.moveToTop();
|
||||||
|
layer.draw();
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
var maxX = stage.width() - 10;
|
||||||
|
var minX = 0;
|
||||||
|
var maxY = stage.height() - 10;
|
||||||
|
var minY = 0;
|
||||||
|
if (isAdding) {
|
||||||
|
// add 10 at a time :)
|
||||||
|
|
||||||
|
for (var i = 0; i < amount; i++) {
|
||||||
|
var bunny = new Konva.Image({
|
||||||
|
image: img,
|
||||||
|
transformsEnabled: 'position',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
listening: false
|
||||||
|
});
|
||||||
|
bunny.speedX = Math.random() * 10;
|
||||||
|
bunny.speedY = Math.random() * 10 - 5;
|
||||||
|
bunnys.push(bunny);
|
||||||
|
layer.add(bunny);
|
||||||
|
counter.text('Bunnies number: ' + bunnys.length);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
topGroup.moveToTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < bunnys.length; i++) {
|
||||||
|
var bunny = bunnys[i];
|
||||||
|
bunny.setX(bunny.getX() + bunny.speedX);
|
||||||
|
bunny.setY(bunny.getY() + bunny.speedY);
|
||||||
|
bunny.speedY += gravity;
|
||||||
|
if (bunny.getX() > maxX - img.width) {
|
||||||
|
bunny.speedX *= -1;
|
||||||
|
bunny.setX(maxX - img.width);
|
||||||
|
} else if (bunny.getX() < minX) {
|
||||||
|
bunny.speedX *= -1;
|
||||||
|
bunny.setX(minX);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bunny.getY() > maxY - img.height) {
|
||||||
|
bunny.speedY *= -0.85;
|
||||||
|
bunny.setY(maxY - img.height);
|
||||||
|
if (Math.random() > 0.5) {
|
||||||
|
bunny.speedY -= Math.random() * 6;
|
||||||
|
}
|
||||||
|
} else if (bunny.getY() < minY) {
|
||||||
|
bunny.speedY = 0;
|
||||||
|
bunny.setY(minY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layer.drawScene();
|
||||||
|
requestAnimationFrame(update);
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
runBunnies();
|
||||||
|
Loading…
Reference in New Issue
Block a user