diff --git a/CHANGELOG.md b/CHANGELOG.md index 922a43a5..be7f89b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## 9.3.20 (2025-03-20) + +- Fix text rendering when ellipses are used + +## 9.3.19 (2025-03-12) + +- Typescript fixes +- Memory leak fixes + ## 9.3.18 (2024-12-23) - Fixed emoji split in multiple lines diff --git a/package.json b/package.json index 6b31ba08..99f554c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "konva", - "version": "9.3.18", + "version": "9.3.20", "description": "HTML5 2d canvas library.", "author": "Anton Lavrenov", "files": [ diff --git a/release.sh b/release.sh index 2b4eedee..57355c8b 100755 --- a/release.sh +++ b/release.sh @@ -49,7 +49,7 @@ echo "build for $1" npm run build >/dev/null git commit -am "build for $1" --allow-empty >/dev/null -echo "update CDN link in REAME" +echo "update CDN link in README" perl -i -pe "s|${old_cdn_min}|${new_cdn_min}|g" ./README.md >/dev/null git commit -am "update cdn link" --allow-empty >/dev/null @@ -61,17 +61,17 @@ git push >/dev/null git push --tags >/dev/null npm publish -echo "copy konva.js into konva-site" -cp ./konva.js ../konva-site/ -cd ../konva-site +# echo "copy konva.js into konva-site" +# cp ./konva.js ../konva-site/ +# cd ../konva-site -echo "replace CDN links" +# echo "replace CDN links" -find source themes/hexo3/layout react-demos vue-demos main-demo -name "*.json" -exec perl -i -pe "s|${old_version}|${new_version}|g" {} + >/dev/null -find source themes/hexo3/layout react-demos vue-demos main-demo -name "*.html" -exec perl -i -pe "s|${old_version}|${new_version}|g" {} + >/dev/null +# find source themes/hexo3/layout react-demos vue-demos main-demo -name "*.json" -exec perl -i -pe "s|${old_version}|${new_version}|g" {} + >/dev/null +# find source themes/hexo3/layout react-demos vue-demos main-demo -name "*.html" -exec perl -i -pe "s|${old_version}|${new_version}|g" {} + >/dev/null -echo "regenerate site" -./deploy.sh >/dev/null +# echo "regenerate site" +# ./deploy.sh >/dev/null echo "DONE!" diff --git a/rollup.config.cjs b/rollup.config.mjs similarity index 96% rename from rollup.config.cjs rename to rollup.config.mjs index 3e7aa510..8d3f7f5c 100644 --- a/rollup.config.cjs +++ b/rollup.config.mjs @@ -1,8 +1,6 @@ // import resolve from 'rollup-plugin-node-resolve'; import typescript from 'rollup-plugin-typescript2'; -const pkg = require('./package.json'); - export default { input: `src/index.ts`, output: [ diff --git a/src/FastLayer.ts b/src/FastLayer.ts index a7f59931..0c782cba 100644 --- a/src/FastLayer.ts +++ b/src/FastLayer.ts @@ -11,7 +11,7 @@ import { _registerNode } from './Global'; * @constructor * @memberof Konva * @augments Konva.Layer - * @@containerParams + @@containerParams * @example * var layer = new Konva.FastLayer(); */ diff --git a/src/shapes/Image.ts b/src/shapes/Image.ts index ae509530..a091b3ec 100644 --- a/src/shapes/Image.ts +++ b/src/shapes/Image.ts @@ -40,9 +40,16 @@ export interface ImageConfig extends ShapeConfig { * imageObj.src = '/path/to/image.jpg' */ export class Image extends Shape { + private _loadListener: () => void; + constructor(attrs: ImageConfig) { super(attrs); - this.on('imageChange.konva', () => { + this._loadListener = () => { + this._requestDraw(); + }; + + this.on('imageChange.konva', (props: any) => { + this._removeImageLoad(props.oldVal); this._setImageLoad(); }); @@ -59,11 +66,19 @@ export class Image extends Shape { return; } if (image && image['addEventListener']) { - image['addEventListener']('load', () => { - this._requestDraw(); - }); + image['addEventListener']('load', this._loadListener); } } + _removeImageLoad(image: any) { + if (image && image['removeEventListener']) { + image['removeEventListener']('load', this._loadListener); + } + } + destroy() { + this._removeImageLoad(this.image()); + super.destroy(); + return this; + } _useBufferCanvas() { const hasCornerRadius = !!this.cornerRadius(); const hasShadow = this.hasShadow(); diff --git a/src/shapes/Text.ts b/src/shapes/Text.ts index 984b553d..eeeb6026 100644 --- a/src/shapes/Text.ts +++ b/src/shapes/Text.ts @@ -534,12 +534,23 @@ export class Text extends Shape { // Convert array indices to string lineArray = stringToArray(line), substr = lineArray.slice(0, mid + 1).join(''), - substrWidth = this._getTextWidth(substr) + additionalWidth; + substrWidth = this._getTextWidth(substr); - if (substrWidth <= maxWidth) { + // Only add ellipsis width when we need to consider truncation + // for the current line (when it might be the last visible line) + const shouldConsiderEllipsis = + shouldAddEllipsis && + fixedHeight && + currentHeightPx + lineHeightPx > maxHeightPx; + + const effectiveWidth = shouldConsiderEllipsis + ? substrWidth + additionalWidth + : substrWidth; + + if (effectiveWidth <= maxWidth) { low = mid + 1; match = substr; - matchWidth = substrWidth; + matchWidth = substrWidth; // Store actual text width without ellipsis } else { high = mid; } diff --git a/test/sandbox.html b/test/sandbox.html index 82bf29e9..bf961d4d 100644 --- a/test/sandbox.html +++ b/test/sandbox.html @@ -17,25 +17,9 @@ padding: 0; margin: 0; } - - .test { - position: absolute; - color: red; - font-size: 20px; - font-family: Arial; - border: 0; - background-color: transparent; - outline: none; - resize: none; - overflow: hidden; - line-height: 1; - padding: 0px; - letter-spacing: 20px; - width: 500px; - text-align: center; - } + @@ -52,36 +36,49 @@ diff --git a/test/unit/Text-test.ts b/test/unit/Text-test.ts index b2d7ea52..f7f76926 100644 --- a/test/unit/Text-test.ts +++ b/test/unit/Text-test.ts @@ -572,7 +572,7 @@ describe('Text', function () { if (isBrowser) { assert.equal( layer.getContext().getTrace(false, true), - "clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);font=normal normal 14px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=black;fillText(HEADING,18,7);restore();save();fillStyle=black;fillText(,50,21);restore();save();fillStyle=black;fillText(All the world's,7,35);restore();save();fillStyle=black;fillText(a stage,,25,49);restore();save();fillStyle=black;fillText(merely,28,63);restore();save();fillStyle=black;fillText(players. They,7,77);restore();save();fillStyle=black;fillText(have…,27,91);restore();restore();" + "clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);font=normal normal 14px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=black;fillText(HEADING,18,7);restore();save();fillStyle=black;fillText(,50,21);restore();save();fillStyle=black;fillText(All the world's a,1,35);restore();save();fillStyle=black;fillText(stage, merely,7,49);restore();save();fillStyle=black;fillText(players. They,7,63);restore();save();fillStyle=black;fillText(have theirrrrrrr,5,77);restore();save();fillStyle=black;fillText(exits and…,14,91);restore();restore();" ); } });