mirror of
https://github.com/konvajs/konva.git
synced 2025-06-27 21:54:37 +08:00
fix caching when buffer is used. close #1886
fix svg length calculation. close #1869
This commit is contained in:
parent
8211db3233
commit
2e08f7319f
@ -1,8 +1,6 @@
|
||||
import { Util } from './Util';
|
||||
import { SceneContext, HitContext, Context } from './Context';
|
||||
import { Konva } from './Global';
|
||||
import { Factory } from './Factory';
|
||||
import { getNumberValidator } from './Validators';
|
||||
|
||||
// calculate pixel ratio
|
||||
let _pixelRatio;
|
||||
|
26
src/Node.ts
26
src/Node.ts
@ -248,8 +248,8 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
*/
|
||||
clearCache() {
|
||||
if (this._cache.has(CANVAS)) {
|
||||
const { scene, filter, hit } = this._cache.get(CANVAS);
|
||||
Util.releaseCanvas(scene, filter, hit);
|
||||
const { scene, filter, hit, buffer } = this._cache.get(CANVAS);
|
||||
Util.releaseCanvas(scene, filter, hit, buffer);
|
||||
this._cache.delete(CANVAS);
|
||||
}
|
||||
|
||||
@ -385,6 +385,18 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
sceneContext = cachedSceneCanvas.getContext(),
|
||||
hitContext = cachedHitCanvas.getContext();
|
||||
|
||||
const bufferCanvas = new SceneCanvas({
|
||||
// width and height already multiplied by pixelRatio
|
||||
// so we need to revert that
|
||||
// also increase size by x nd y offset to make sure content fits canvas
|
||||
width:
|
||||
cachedSceneCanvas.width / cachedSceneCanvas.pixelRatio + Math.abs(x),
|
||||
height:
|
||||
cachedSceneCanvas.height / cachedSceneCanvas.pixelRatio + Math.abs(y),
|
||||
pixelRatio: cachedSceneCanvas.pixelRatio,
|
||||
}),
|
||||
bufferContext = bufferCanvas.getContext();
|
||||
|
||||
cachedHitCanvas.isCache = true;
|
||||
cachedSceneCanvas.isCache = true;
|
||||
|
||||
@ -398,16 +410,23 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
|
||||
sceneContext.save();
|
||||
hitContext.save();
|
||||
bufferContext.save();
|
||||
|
||||
sceneContext.translate(-x, -y);
|
||||
hitContext.translate(-x, -y);
|
||||
bufferContext.translate(-x, -y);
|
||||
// hard-code offset to make sure content fits canvas
|
||||
// @ts-ignore
|
||||
bufferCanvas.x = x;
|
||||
// @ts-ignore
|
||||
bufferCanvas.y = y;
|
||||
|
||||
// extra flag to skip on getAbsolute opacity calc
|
||||
this._isUnderCache = true;
|
||||
this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY);
|
||||
this._clearSelfAndDescendantCache(ABSOLUTE_SCALE);
|
||||
|
||||
this.drawScene(cachedSceneCanvas, this);
|
||||
this.drawScene(cachedSceneCanvas, this, bufferCanvas);
|
||||
this.drawHit(cachedHitCanvas, this);
|
||||
this._isUnderCache = false;
|
||||
|
||||
@ -431,6 +450,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
scene: cachedSceneCanvas,
|
||||
filter: cachedFilterCanvas,
|
||||
hit: cachedHitCanvas,
|
||||
buffer: bufferCanvas,
|
||||
x: x,
|
||||
y: y,
|
||||
});
|
||||
|
10
src/Shape.ts
10
src/Shape.ts
@ -602,7 +602,7 @@ export class Shape<
|
||||
stage,
|
||||
bufferContext;
|
||||
|
||||
const skipBuffer = canvas.isCache;
|
||||
const skipBuffer = false;
|
||||
const cachingSelf = top === this;
|
||||
|
||||
if (!this.isVisible() && !cachingSelf) {
|
||||
@ -646,7 +646,13 @@ export class Shape<
|
||||
}
|
||||
context._applyOpacity(this);
|
||||
context._applyGlobalCompositeOperation(this);
|
||||
context.drawImage(bc._canvas, 0, 0, bc.width / ratio, bc.height / ratio);
|
||||
context.drawImage(
|
||||
bc._canvas,
|
||||
bc.x || 0,
|
||||
bc.y || 0,
|
||||
bc.width / ratio,
|
||||
bc.height / ratio
|
||||
);
|
||||
} else {
|
||||
context._applyLineJoin(this);
|
||||
|
||||
|
@ -258,11 +258,19 @@ export class Path extends Shape<PathConfig> {
|
||||
}
|
||||
|
||||
if (length < 0.01) {
|
||||
points = dataArray[i].points.slice(0, 2);
|
||||
return {
|
||||
x: points[0],
|
||||
y: points[1],
|
||||
};
|
||||
const cmd = dataArray[i].command;
|
||||
if (cmd === 'M') {
|
||||
points = dataArray[i].points.slice(0, 2);
|
||||
return {
|
||||
x: points[0],
|
||||
y: points[1],
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
x: dataArray[i].start.x,
|
||||
y: dataArray[i].start.y,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const cp = dataArray[i];
|
||||
|
@ -1083,6 +1083,7 @@ describe('Path', function () {
|
||||
it('get point at path', function () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
const data =
|
||||
'M 300,10 L 250,100 A 100 40 30 1 0 150 150 C 160,100, 290,100, 300,150';
|
||||
var path = new Konva.Path({
|
||||
@ -1102,7 +1103,7 @@ describe('Path', function () {
|
||||
var circle = new Konva.Circle({
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
radius: 2,
|
||||
radius: 0.1,
|
||||
fill: 'black',
|
||||
stroke: 'black',
|
||||
});
|
||||
@ -1164,13 +1165,49 @@ describe('Path', function () {
|
||||
{ x: 299.87435436448743, y: 149.4028482225714 },
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('get point at vertical path', function () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
const data = 'M 614.96002,7.5147864 611.20262,429.59529';
|
||||
var path = new Konva.Path({
|
||||
stroke: 'red',
|
||||
strokeWidth: 3,
|
||||
data,
|
||||
x: -600,
|
||||
});
|
||||
layer.add(path);
|
||||
if (isBrowser) {
|
||||
const SVGPath = document.createElementNS(
|
||||
'http://www.w3.org/2000/svg',
|
||||
'path'
|
||||
) as SVGPathElement;
|
||||
SVGPath.setAttribute('d', data);
|
||||
for (var i = 0.001; i < path.getLength(); i += 1) {
|
||||
var p = path.getPointAtLength(i);
|
||||
console.log(p);
|
||||
var circle = new Konva.Circle({
|
||||
x: p.x + path.x(),
|
||||
y: p.y + path.y(),
|
||||
radius: 2,
|
||||
fill: 'black',
|
||||
stroke: 'black',
|
||||
});
|
||||
layer.add(circle);
|
||||
const position = SVGPath.getPointAtLength(i);
|
||||
console.log(position);
|
||||
assert(Math.abs(p.x - position.x) <= 1);
|
||||
assert(Math.abs(p.y - position.y) <= 1);
|
||||
}
|
||||
}
|
||||
stage.add(layer);
|
||||
});
|
||||
|
||||
it('get point at path with float attrs', function () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const data =
|
||||
'M419.0000314094981 342.88624187900973 L419.00003140949804 577.0038889378335 L465.014001082264 577.0038889378336 Z';
|
||||
|
@ -1597,6 +1597,36 @@ describe('Shape', function () {
|
||||
compareCanvases(canvas1, canvas2, 240, 110);
|
||||
});
|
||||
|
||||
it('check stroke rendering on buffer canvas', async function () {
|
||||
var stage = addStage();
|
||||
|
||||
var layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const rect = new Konva.Rect({
|
||||
x: 150,
|
||||
y: 50,
|
||||
width: 50,
|
||||
height: 50,
|
||||
fill: '#039BE5',
|
||||
stroke: 'yellow',
|
||||
strokeWidth: 5,
|
||||
shadowColor: 'black',
|
||||
shadowOffset: { x: 10, y: 10 },
|
||||
shadowOpacity: 0.5,
|
||||
});
|
||||
|
||||
layer.add(rect);
|
||||
|
||||
const canvas1 = layer.toCanvas();
|
||||
rect.cache();
|
||||
const canvas2 = layer.toCanvas();
|
||||
|
||||
// throw new Error('stop');
|
||||
|
||||
compareCanvases(canvas1, canvas2);
|
||||
});
|
||||
|
||||
// ======================================================
|
||||
it('optional disable shadow for stroke', function () {
|
||||
var stage = addStage();
|
||||
|
@ -131,6 +131,14 @@ export function compareCanvases(canvas1, canvas2, tol?, secondTol?) {
|
||||
b.appendChild(canvas2);
|
||||
c.appendChild(diffCanvas);
|
||||
div.appendChild(b);
|
||||
if (!canvas1.parentNode) {
|
||||
const d = get('div', '<div>Original:</div>');
|
||||
canvas1.style.position = '';
|
||||
canvas1.style.display = '';
|
||||
d.style.float = 'left';
|
||||
d.appendChild(canvas1);
|
||||
div.appendChild(d);
|
||||
}
|
||||
div.appendChild(c);
|
||||
getContainer().appendChild(div);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user