Merge branch 'master' into config-window-global

This commit is contained in:
Anton Lavrenov 2022-11-16 22:33:52 -05:00 committed by GitHub
commit 0a5c510ade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1572 additions and 1462 deletions

View File

@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
### 8.3.14 (2022-11-09)
- Automatically release (destroy) used canvas elements. Should fix safari memory issues
### 8.3.13 (2022-10-03)
- Typescript fixes
- Better non-passive events usage
- Better 2d context usage to avoid Chrome warnings
### 8.3.12 (2022-08-29) ### 8.3.12 (2022-08-29)
- `ellipsis` fixes for `Konva.Text` - `ellipsis` fixes for `Konva.Text`

2893
konva.js

File diff suppressed because it is too large Load Diff

6
konva.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "konva", "name": "konva",
"version": "8.3.12", "version": "8.3.14",
"author": "Anton Lavrenov", "author": "Anton Lavrenov",
"files": [ "files": [
"README.md", "README.md",

View File

@ -23,6 +23,7 @@ function getDevicePixelRatio() {
1; 1;
return devicePixelRatio / backingStoreRatio; return devicePixelRatio / backingStoreRatio;
})(); })();
Util.releaseCanvas(canvas);
return _pixelRatio; return _pixelRatio;
} }

View File

@ -86,7 +86,7 @@ var CONTEXT_PROPERTIES = [
'globalAlpha', 'globalAlpha',
'globalCompositeOperation', 'globalCompositeOperation',
'imageSmoothingEnabled', 'imageSmoothingEnabled',
]; ] as const;
const traceArrMax = 100; const traceArrMax = 100;
/** /**
@ -118,7 +118,6 @@ export class Context {
constructor(canvas: Canvas) { constructor(canvas: Canvas) {
this.canvas = canvas; this.canvas = canvas;
this._context = canvas._canvas.getContext('2d') as CanvasRenderingContext2D;
if (Konva.enableTrace) { if (Konva.enableTrace) {
this.traceArr = []; this.traceArr = [];
@ -702,6 +701,11 @@ export class Context {
} }
} }
// supported context properties
type CanvasContextProps = Pick<CanvasRenderingContext2D, typeof CONTEXT_PROPERTIES[number]>;
export interface Context extends CanvasContextProps {};
CONTEXT_PROPERTIES.forEach(function (prop) { CONTEXT_PROPERTIES.forEach(function (prop) {
Object.defineProperty(Context.prototype, prop, { Object.defineProperty(Context.prototype, prop, {
get() { get() {
@ -714,6 +718,10 @@ CONTEXT_PROPERTIES.forEach(function (prop) {
}); });
export class SceneContext extends Context { export class SceneContext extends Context {
constructor(canvas: Canvas) {
super(canvas);
this._context = canvas._canvas.getContext('2d') as CanvasRenderingContext2D;
}
_fillColor(shape: Shape) { _fillColor(shape: Shape) {
var fill = shape.fill(); var fill = shape.fill();
@ -853,6 +861,12 @@ export class SceneContext extends Context {
} }
export class HitContext extends Context { export class HitContext extends Context {
constructor(canvas: Canvas) {
super(canvas);
this._context = canvas._canvas.getContext('2d', {
willReadFrequently: true,
}) as CanvasRenderingContext2D;
}
_fill(shape) { _fill(shape) {
this.save(); this.save();
this.setAttr('fillStyle', shape.colorKey); this.setAttr('fillStyle', shape.colorKey);

View File

@ -164,6 +164,17 @@ export const Konva = {
isDragReady() { isDragReady() {
return !!Konva['DD'].node; return !!Konva['DD'].node;
}, },
/**
* Should Konva release canvas elements on destroy. Default is true.
* Useful to avoid memory leak issues in Safari on macOS/iOS.
* @property releaseCanvasOnDestroy
* @default true
* @name releaseCanvasOnDestroy
* @memberof Konva
* @example
* Konva.releaseCanvasOnDestroy = true;
*/
releaseCanvasOnDestroy: true,
// user agent // user agent
document: glob.document, document: glob.document,
// insert Konva into global namespace (window) // insert Konva into global namespace (window)

View File

@ -468,6 +468,11 @@ export class Layer extends Container<Group | Shape> {
} }
} }
destroy(): this {
Util.releaseCanvas(this.getNativeCanvasElement(), this.getHitCanvas()._canvas);
return super.destroy();
}
hitGraphEnabled: GetSet<boolean, this>; hitGraphEnabled: GetSet<boolean, this>;
clearBeforeDraw: GetSet<boolean, this>; clearBeforeDraw: GetSet<boolean, this>;

View File

@ -57,7 +57,7 @@ export interface NodeConfig {
listening?: boolean; listening?: boolean;
id?: string; id?: string;
name?: string; name?: string;
opacity?: Number; opacity?: number;
scale?: Vector2d; scale?: Vector2d;
scaleX?: number; scaleX?: number;
scaleY?: number; scaleY?: number;
@ -243,7 +243,12 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
* node.clearCache(); * node.clearCache();
*/ */
clearCache() { clearCache() {
this._cache.delete(CANVAS); if (this._cache.has(CANVAS)) {
const { scene, filter, hit } = this._cache.get(CANVAS);
Util.releaseCanvas(scene, filter, hit);
this._cache.delete(CANVAS);
}
this._clearSelfAndDescendantCache(); this._clearSelfAndDescendantCache();
this._requestDraw(); this._requestDraw();
return this; return this;
@ -853,6 +858,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
*/ */
destroy() { destroy() {
this.remove(); this.remove();
this.clearCache();
return this; return this;
} }
/** /**

View File

@ -280,6 +280,9 @@ export class Stage extends Container<Layer> {
if (index > -1) { if (index > -1) {
stages.splice(index, 1); stages.splice(index, 1);
} }
Util.releaseCanvas(this.bufferCanvas._canvas, this.bufferHitCanvas._canvas)
return this; return this;
} }
/** /**
@ -461,9 +464,13 @@ export class Stage extends Container<Layer> {
return; return;
} }
EVENTS.forEach(([event, methodName]) => { EVENTS.forEach(([event, methodName]) => {
this.content.addEventListener(event, (evt) => { this.content.addEventListener(
this[methodName](evt); event,
}); (evt) => {
this[methodName](evt);
},
{ passive: false }
);
}); });
} }
_pointerenter(evt) { _pointerenter(evt) {

View File

@ -957,4 +957,12 @@ export const Util = {
return evt.changedTouches[0].identifier; return evt.changedTouches[0].identifier;
} }
}, },
releaseCanvas(...canvases: HTMLCanvasElement[]) {
if (!Konva.releaseCanvasOnDestroy) return;
canvases.forEach(c => {
c.width = 0;
c.height = 0;
})
}
}; };

View File

@ -197,7 +197,7 @@ export const Kaleidoscope: Filter = function (imageData) {
var scratchData = tempCanvas var scratchData = tempCanvas
.getContext('2d') .getContext('2d')
.getImageData(0, 0, xSize, ySize); .getImageData(0, 0, xSize, ySize);
Util.releaseCanvas(tempCanvas);
// Convert thhe original to polar coordinates // Convert thhe original to polar coordinates
ToPolar(imageData, scratchData, { ToPolar(imageData, scratchData, {
polarCenterX: xSize / 2, polarCenterX: xSize / 2,

View File

@ -7,7 +7,6 @@ import { _registerNode } from '../Global';
export interface RingConfig extends ShapeConfig { export interface RingConfig extends ShapeConfig {
innerRadius: number; innerRadius: number;
outerRadius: number; outerRadius: number;
clockwise?: boolean;
} }
var PIx2 = Math.PI * 2; var PIx2 = Math.PI * 2;
@ -19,7 +18,6 @@ var PIx2 = Math.PI * 2;
* @param {Object} config * @param {Object} config
* @param {Number} config.innerRadius * @param {Number} config.innerRadius
* @param {Number} config.outerRadius * @param {Number} config.outerRadius
* @param {Boolean} [config.clockwise]
* @@shapeParams * @@shapeParams
* @@nodeParams * @@nodeParams
* @example * @example

View File

@ -533,6 +533,10 @@ export class TextPath extends Shape<TextPathConfig> {
height: maxY - minY + fontSize, height: maxY - minY + fontSize,
}; };
} }
destroy(): this {
Util.releaseCanvas(this.dummyCanvas);
return super.destroy();
}
fontFamily: GetSet<string, this>; fontFamily: GetSet<string, this>;
fontSize: GetSet<number, this>; fontSize: GetSet<number, this>;

View File

@ -1327,8 +1327,8 @@ Factory.addGetterSetter(
* get/set resize ability. If false it will automatically hide resizing handlers * get/set resize ability. If false it will automatically hide resizing handlers
* @name Konva.Transformer#resizeEnabled * @name Konva.Transformer#resizeEnabled
* @method * @method
* @param {Array} array * @param {Boolean} enabled
* @returns {Array} * @returns {Boolean}
* @example * @example
* // get * // get
* var resizeEnabled = transformer.resizeEnabled(); * var resizeEnabled = transformer.resizeEnabled();
@ -1339,9 +1339,9 @@ Factory.addGetterSetter(
Factory.addGetterSetter(Transformer, 'resizeEnabled', true); Factory.addGetterSetter(Transformer, 'resizeEnabled', true);
/** /**
* get/set anchor size. Default is 10 * get/set anchor size. Default is 10
* @name Konva.Transformer#validateAnchors * @name Konva.Transformer#anchorSize
* @method * @method
* @param {Number} 10 * @param {Number} size
* @returns {Number} * @returns {Number}
* @example * @example
* // get * // get
@ -1441,8 +1441,8 @@ Factory.addGetterSetter(Transformer, 'borderEnabled', true);
* get/set anchor stroke color * get/set anchor stroke color
* @name Konva.Transformer#anchorStroke * @name Konva.Transformer#anchorStroke
* @method * @method
* @param {Boolean} enabled * @param {String} strokeColor
* @returns {Boolean} * @returns {String}
* @example * @example
* // get * // get
* var anchorStroke = transformer.anchorStroke(); * var anchorStroke = transformer.anchorStroke();
@ -1456,8 +1456,8 @@ Factory.addGetterSetter(Transformer, 'anchorStroke', 'rgb(0, 161, 255)');
* get/set anchor stroke width * get/set anchor stroke width
* @name Konva.Transformer#anchorStrokeWidth * @name Konva.Transformer#anchorStrokeWidth
* @method * @method
* @param {Boolean} enabled * @param {Number} anchorStrokeWidth
* @returns {Boolean} * @returns {Number}
* @example * @example
* // get * // get
* var anchorStrokeWidth = transformer.anchorStrokeWidth(); * var anchorStrokeWidth = transformer.anchorStrokeWidth();
@ -1476,8 +1476,8 @@ Factory.addGetterSetter(
* get/set anchor fill color * get/set anchor fill color
* @name Konva.Transformer#anchorFill * @name Konva.Transformer#anchorFill
* @method * @method
* @param {Boolean} enabled * @param {String} anchorFill
* @returns {Boolean} * @returns {String}
* @example * @example
* // get * // get
* var anchorFill = transformer.anchorFill(); * var anchorFill = transformer.anchorFill();
@ -1491,7 +1491,7 @@ Factory.addGetterSetter(Transformer, 'anchorFill', 'white');
* get/set anchor corner radius * get/set anchor corner radius
* @name Konva.Transformer#anchorCornerRadius * @name Konva.Transformer#anchorCornerRadius
* @method * @method
* @param {Number} enabled * @param {Number} radius
* @returns {Number} * @returns {Number}
* @example * @example
* // get * // get
@ -1526,8 +1526,8 @@ Factory.addGetterSetter(Transformer, 'borderStroke', 'rgb(0, 161, 255)');
* get/set border stroke width * get/set border stroke width
* @name Konva.Transformer#borderStrokeWidth * @name Konva.Transformer#borderStrokeWidth
* @method * @method
* @param {Boolean} enabled * @param {Number} strokeWidth
* @returns {Boolean} * @returns {Number}
* @example * @example
* // get * // get
* var borderStrokeWidth = transformer.borderStrokeWidth(); * var borderStrokeWidth = transformer.borderStrokeWidth();
@ -1546,8 +1546,8 @@ Factory.addGetterSetter(
* get/set border dash array * get/set border dash array
* @name Konva.Transformer#borderDash * @name Konva.Transformer#borderDash
* @method * @method
* @param {Boolean} enabled * @param {Array} dash array
* @returns {Boolean} * @returns {Array}
* @example * @example
* // get * // get
* var borderDash = transformer.borderDash(); * var borderDash = transformer.borderDash();

View File

@ -45,10 +45,13 @@
fill: 'red', fill: 'red',
}); });
layer.add(rect); layer.add(rect);
stage.on('wheel', (e) => {
document.body.onclick = () => { e.evt.preventDefault();
alert('click'); console.log('wheel');
}; });
stage.on('contextmenu', (e) => {
console.log('click');
});
</script> </script>
</body> </body>
</html> </html>

View File

@ -57,7 +57,7 @@ describe('Context', function () {
'textBaseline', 'textBaseline',
'globalAlpha', 'globalAlpha',
'globalCompositeOperation', 'globalCompositeOperation',
]; ] as const;
it('context wrapper should work like native context', function () { it('context wrapper should work like native context', function () {
var stage = addStage(); var stage = addStage();
@ -108,10 +108,10 @@ describe('Context', function () {
// test get // test get
nativeContext.fillStyle = '#ff0000'; nativeContext.fillStyle = '#ff0000';
assert.equal(context['fillStyle'], '#ff0000'); assert.equal(context.fillStyle, '#ff0000');
// test set // test set
context['globalAlpha'] = 0.5; context.globalAlpha = 0.5;
assert.equal(context['globalAlpha'], 0.5); assert.equal(context.globalAlpha, 0.5);
}); });
}); });