From 21941ce2cd517fc0f86520ae38d29f2d08ee6eda Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Tue, 11 Feb 2020 07:55:14 +1300
Subject: [PATCH 01/16] Refactored pathGraphics example to easily support
rendering path bounding boxes
---
examples/Graphics/pathGraphics.ts | 70 ++++++++++++++++---------------
1 file changed, 36 insertions(+), 34 deletions(-)
diff --git a/examples/Graphics/pathGraphics.ts b/examples/Graphics/pathGraphics.ts
index ae9da0b..98eb1d9 100755
--- a/examples/Graphics/pathGraphics.ts
+++ b/examples/Graphics/pathGraphics.ts
@@ -1,54 +1,56 @@
import createHiDPICanvas from "../../lib/hidpi-canvas";
+
+function createPathShape(path, strokeColor, fillColor = null) {
+ const shape = new createjs.Shape();
+
+ if (fillColor) {
+ shape.graphics.beginFill(fillColor);
+ }
+ shape.graphics
+ .setStrokeStyle(4)
+ .beginStroke(strokeColor)
+ .decodeSVGPath(path);
+
+ return shape;
+}
+
export default function init() {
const canvas = createHiDPICanvas(1080, 420, 1);
document.body.appendChild(canvas);
const stage = new createjs.Stage(canvas);
- const a = new createjs.Shape();
- a.graphics.setStrokeStyle(4);
- a.graphics.beginStroke("#00F");
- a.graphics.beginFill("#F00");
- a.graphics.decodeSVGPath("M 300 200 h -150 a 150 150 0 1 0 150 -150 z");
+ const a = createPathShape(
+ "M 300 200 h -150 a 150 150 0 1 0 150 -150 z",
+ "#00F",
+ "#F00"
+ );
stage.addChild(a);
- const b = new createjs.Shape();
- b.graphics.setStrokeStyle(4);
- b.graphics.beginStroke("#000");
- b.graphics.beginFill("#FF0");
- b.graphics.decodeSVGPath("M 275 175 v -150 a 150 150 0 0 0 -150 150 z");
+ const b = createPathShape(
+ "M 275 175 v -150 a 150 150 0 0 0 -150 150 z",
+ "#000",
+ "#FF0"
+ );
+
stage.addChild(b);
- const c = new createjs.Shape();
- c.graphics.setStrokeStyle(4);
- c.graphics.beginStroke("#F00");
- c.graphics.decodeSVGPath(
- "M 600 400 l 50 -25 a25 25 -30 0 1 50 -25 l 50 -25 a25 50 -30 0 1 50 -25 l 50 -25 a25 75 -30 0 1 50 -25 l 50 -25 a 25 100 -30 0 1 50 -25 l50 -25"
+ const c = createPathShape(
+ "M 600 400 l 50 -25 a25 25 -30 0 1 50 -25 l 50 -25 a25 50 -30 0 1 50 -25 l 50 -25 a25 75 -30 0 1 50 -25 l 50 -25 a 25 100 -30 0 1 50 -25 l50 -25",
+ "#F00"
);
stage.addChild(c);
- let d = new createjs.Shape();
- d.graphics.setStrokeStyle(4);
- d.graphics.beginStroke("#F00");
- d.graphics.decodeSVGPath("M 600,75 a100,50 0 0,0 100,50");
+ const d = createPathShape("M 600,75 a100,50 0 0,0 100,50", "#F00");
stage.addChild(d);
- d = new createjs.Shape();
- d.graphics.setStrokeStyle(4);
- d.graphics.beginStroke("#0F0");
- d.graphics.decodeSVGPath("M 600,75 a100,50 0 0,1 100,50");
- stage.addChild(d);
+ const e = createPathShape("M 600,75 a100,50 0 0,1 100,50", "#0F0");
+ stage.addChild(e);
- d = new createjs.Shape();
- d.graphics.setStrokeStyle(4);
- d.graphics.beginStroke("#00F");
- d.graphics.decodeSVGPath("M 600,75 a100,50 0 1,0 100,50");
- stage.addChild(d);
+ const f = createPathShape("M 600,75 a100,50 0 1,0 100,50", "#00F");
+ stage.addChild(f);
- d = new createjs.Shape();
- d.graphics.setStrokeStyle(4);
- d.graphics.beginStroke("#F0F");
- d.graphics.decodeSVGPath("M 600,75 a100,50 0 1,1 100,50");
- stage.addChild(d);
+ const g = createPathShape("M 600,75 a100,50 0 1,1 100,50", "#F0F");
+ stage.addChild(g);
stage.update();
return stage;
From 5daae68f5ee708c135dc610580cdc56b5bc3b9a3 Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Tue, 11 Feb 2020 16:51:31 +1300
Subject: [PATCH 02/16] Inital work on gettin bounds for SVG Paths
---
examples/Graphics/bounding_box.ts | 29 +++
examples/Graphics/pathGraphics.ts | 10 +
examples/graphics.ts | 3 +-
index.html | 3 +
src/Character.ts | 2 +
src/Glyph.ts | 35 ++-
src/Graphics.ts | 2 +-
src/PathBounds.ts | 342 ++++++++++++++++++++++++++++++
src/SVGPath.ts | 22 +-
src/index.ts | 4 +-
tests/get-bounds.js | 47 ++++
11 files changed, 493 insertions(+), 6 deletions(-)
create mode 100644 examples/Graphics/bounding_box.ts
create mode 100644 src/PathBounds.ts
create mode 100644 tests/get-bounds.js
diff --git a/examples/Graphics/bounding_box.ts b/examples/Graphics/bounding_box.ts
new file mode 100644
index 0000000..4041039
--- /dev/null
+++ b/examples/Graphics/bounding_box.ts
@@ -0,0 +1,29 @@
+import createHiDPICanvas from "../../lib/hidpi-canvas";
+import svgPath from "../fixtures/svg-glyph";
+export default function init() {
+ let canvas = createHiDPICanvas(1000, 1000, 2);
+ document.body.appendChild(canvas);
+ let stage = new createjs.Stage(canvas);
+
+ var shape = new createjs.Shape();
+
+ shape.graphics.beginFill("#000");
+ shape.graphics.decodeSVGPath(svgPath);
+ shape.graphics.endFill();
+ shape.y = 30;
+ stage.addChild(shape);
+
+ var boundingBox = new createjs.Rectangle();
+ boundingBox = txt.svgPathBoundingBox(svgPath);
+ var boundaryLine = new createjs.Shape();
+ boundaryLine.y = 30;
+ boundaryLine.graphics
+ .beginStroke("#dd0000")
+ .setStrokeStyle(2)
+ .setStrokeDash([15, 5])
+ .rect(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height);
+ stage.addChild(boundaryLine);
+
+ stage.update();
+ return stage;
+}
diff --git a/examples/Graphics/pathGraphics.ts b/examples/Graphics/pathGraphics.ts
index 98eb1d9..97b8af3 100755
--- a/examples/Graphics/pathGraphics.ts
+++ b/examples/Graphics/pathGraphics.ts
@@ -11,6 +11,16 @@ function createPathShape(path, strokeColor, fillColor = null) {
.beginStroke(strokeColor)
.decodeSVGPath(path);
+ let bounds = txt.svgPathBoundingBox(path);
+ shape.setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
+
+ shape.graphics
+ .endFill()
+ .setStrokeStyle(1)
+ .setStrokeDash([20, 10], 0)
+ .beginStroke("#93F")
+ .drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
+
return shape;
}
diff --git a/examples/graphics.ts b/examples/graphics.ts
index 261da33..2ae08e5 100644
--- a/examples/graphics.ts
+++ b/examples/graphics.ts
@@ -1,5 +1,6 @@
import pathGraphics from "./Graphics/pathGraphics";
import pathGraphics2 from "./Graphics/pathGraphics2";
import pathGraphics3 from "./Graphics/pathGraphics3";
+import bounding_box from "./Graphics/bounding_box";
-export default { pathGraphics, pathGraphics2, pathGraphics3 };
+export default { pathGraphics, pathGraphics2, pathGraphics3, bounding_box };
diff --git a/index.html b/index.html
index 6accee6..5dcc743 100644
--- a/index.html
+++ b/index.html
@@ -312,6 +312,9 @@ Graphics
Glyph Rendering (inverted)
+
+ SVG Path Bounds
+
diff --git a/src/Character.ts b/src/Character.ts
index ba10ef5..6e5be03 100644
--- a/src/Character.ts
+++ b/src/Character.ts
@@ -119,6 +119,8 @@ export default class Character extends createjs.Shape {
this._font.ascent - this._font.descent
);
this.hitArea = ha;
+
+ this._glyph.boundingLine();
}
setGlyph(glyph: Glyph) {
diff --git a/src/Glyph.ts b/src/Glyph.ts
index 16c4a2e..ed39681 100755
--- a/src/Glyph.ts
+++ b/src/Glyph.ts
@@ -1,17 +1,23 @@
+import { svgPathBoundingBox } from "./SVGPath";
+
/**
* Represents a single Glyph within a Font.
*/
-
export default class Glyph {
/** SVG path data */
path = "";
+ private _bounds: createjs.Rectangle = null;
offset: number;
kerning: any = {};
+
private _graphic: createjs.Graphics = null;
+ private _boundaryLine: createjs.Graphics = null;
_fill: createjs.Graphics.Fill;
_stroke: createjs.Graphics.Stroke;
_strokeStyle: createjs.Graphics.StrokeStyle;
+ static debug: false;
+
graphic() {
if (this._graphic == null) {
this._graphic = new createjs.Graphics();
@@ -39,8 +45,35 @@ export default class Glyph {
return this._graphic;
}
+ getBounds() {
+ if (!this._bounds) {
+ this._bounds = svgPathBoundingBox(this.path);
+ }
+ return this._bounds;
+ }
+
+ boundingLine() {
+ if (this._boundaryLine == null) {
+ this._boundaryLine = new createjs.Graphics();
+ let bounds = this.getBounds();
+ this._boundaryLine.append(
+ new createjs.Graphics.Rect(
+ bounds.x,
+ bounds.y,
+ bounds.width,
+ bounds.height
+ )
+ );
+ this._boundaryLine.append(new createjs.Graphics.StrokeDash([10, 4]));
+ this._boundaryLine.append(new createjs.Graphics.Stroke("#FF00FF", true));
+ }
+ }
+
draw(ctx: CanvasRenderingContext2D): boolean {
this._graphic.draw(ctx);
+ if (Glyph.debug) {
+ this._boundaryLine.draw(ctx);
+ }
return true;
}
diff --git a/src/Graphics.ts b/src/Graphics.ts
index 75c3cc9..8a61a93 100644
--- a/src/Graphics.ts
+++ b/src/Graphics.ts
@@ -1,5 +1,5 @@
import SVGArc from "./SVGArc";
-import { parsePathData } from "./SVGPath";
+import { parsePathData, svgPathBoundingBox } from "./SVGPath";
export default class Graphics {
/**
diff --git a/src/PathBounds.ts b/src/PathBounds.ts
new file mode 100644
index 0000000..fe9f68d
--- /dev/null
+++ b/src/PathBounds.ts
@@ -0,0 +1,342 @@
+function getBoundsOfCurve(x, y, x1, y1, x2, y2, tempX, tempY) {
+ // TODO: implement getBoundsOfCurve
+ return [];
+}
+
+function getBoundsOfArc(fx, fy, rx, ry, rot, large, sweep, tx, ty) {
+ // TODO: implement getBoundsOfArc
+ return [];
+}
+
+export default function pathBounds(path) {
+ let aX = [],
+ aY = [],
+ current, // current instruction
+ previous = null,
+ subpathStartX = 0,
+ subpathStartY = 0,
+ x = 0, // current x
+ y = 0, // current y
+ controlX = 0, // current control point x
+ controlY = 0, // current control point y
+ tempX,
+ tempY,
+ bounds;
+
+ for (var i = 0, len = path.length; i < len; ++i) {
+ current = path[i].points.flat();
+
+ current.unshift(path[i].command);
+
+ switch (
+ path[i].command // first letter
+ ) {
+ case "l": // lineto, relative
+ x += current[1];
+ y += current[2];
+ bounds = [];
+ break;
+
+ case "L": // lineto, absolute
+ x = current[1];
+ y = current[2];
+ bounds = [];
+ break;
+
+ case "h": // horizontal lineto, relative
+ x += current[1];
+ bounds = [];
+ break;
+
+ case "H": // horizontal lineto, absolute
+ x = current[1];
+ bounds = [];
+ break;
+
+ case "v": // vertical lineto, relative
+ y += current[1];
+ bounds = [];
+ break;
+
+ case "V": // verical lineto, absolute
+ y = current[1];
+ bounds = [];
+ break;
+
+ case "m": // moveTo, relative
+ x += current[1];
+ y += current[2];
+ subpathStartX = x;
+ subpathStartY = y;
+ bounds = [];
+ break;
+
+ case "M": // moveTo, absolute
+ x = current[1];
+ y = current[2];
+ subpathStartX = x;
+ subpathStartY = y;
+ bounds = [];
+ break;
+
+ case "c": // bezierCurveTo, relative
+ tempX = x + current[5];
+ tempY = y + current[6];
+ controlX = x + current[3];
+ controlY = y + current[4];
+ bounds = getBoundsOfCurve(
+ x,
+ y,
+ x + current[1], // x1
+ y + current[2], // y1
+ controlX, // x2
+ controlY, // y2
+ tempX,
+ tempY
+ );
+ x = tempX;
+ y = tempY;
+ break;
+
+ case "C": // bezierCurveTo, absolute
+ controlX = current[3];
+ controlY = current[4];
+ bounds = getBoundsOfCurve(
+ x,
+ y,
+ current[1],
+ current[2],
+ controlX,
+ controlY,
+ current[5],
+ current[6]
+ );
+ x = current[5];
+ y = current[6];
+ break;
+
+ case "s": // shorthand cubic bezierCurveTo, relative
+ // transform to absolute x,y
+ tempX = x + current[3];
+ tempY = y + current[4];
+
+ if (previous[0].match(/[CcSs]/) === null) {
+ // If there is no previous command or if the previous command was not a C, c, S, or s,
+ // the control point is coincident with the current point
+ controlX = x;
+ controlY = y;
+ } else {
+ // calculate reflection of previous control points
+ controlX = 2 * x - controlX;
+ controlY = 2 * y - controlY;
+ }
+
+ bounds = getBoundsOfCurve(
+ x,
+ y,
+ controlX,
+ controlY,
+ x + current[1],
+ y + current[2],
+ tempX,
+ tempY
+ );
+ // set control point to 2nd one of this command
+ // "... the first control point is assumed to be
+ // the reflection of the second control point on
+ // the previous command relative to the current point."
+ controlX = x + current[1];
+ controlY = y + current[2];
+ x = tempX;
+ y = tempY;
+ break;
+
+ case "S": // shorthand cubic bezierCurveTo, absolute
+ tempX = current[3];
+ tempY = current[4];
+ if (previous[0].match(/[CcSs]/) === null) {
+ // If there is no previous command or if the previous command was not a C, c, S, or s,
+ // the control point is coincident with the current point
+ controlX = x;
+ controlY = y;
+ } else {
+ // calculate reflection of previous control points
+ controlX = 2 * x - controlX;
+ controlY = 2 * y - controlY;
+ }
+ bounds = getBoundsOfCurve(
+ x,
+ y,
+ controlX,
+ controlY,
+ current[1],
+ current[2],
+ tempX,
+ tempY
+ );
+ x = tempX;
+ y = tempY;
+ // set control point to 2nd one of this command
+ // "... the first control point is assumed to be
+ // the reflection of the second control point on
+ // the previous command relative to the current point."
+ controlX = current[1];
+ controlY = current[2];
+ break;
+
+ case "q": // quadraticCurveTo, relative
+ // transform to absolute x,y
+ tempX = x + current[3];
+ tempY = y + current[4];
+ controlX = x + current[1];
+ controlY = y + current[2];
+ bounds = getBoundsOfCurve(
+ x,
+ y,
+ controlX,
+ controlY,
+ controlX,
+ controlY,
+ tempX,
+ tempY
+ );
+ x = tempX;
+ y = tempY;
+ break;
+
+ case "Q": // quadraticCurveTo, absolute
+ controlX = current[1];
+ controlY = current[2];
+ bounds = getBoundsOfCurve(
+ x,
+ y,
+ controlX,
+ controlY,
+ controlX,
+ controlY,
+ current[3],
+ current[4]
+ );
+ x = current[3];
+ y = current[4];
+ break;
+
+ case "t": // shorthand quadraticCurveTo, relative
+ // transform to absolute x,y
+ tempX = x + current[1];
+ tempY = y + current[2];
+ if (previous[0].match(/[QqTt]/) === null) {
+ // If there is no previous command or if the previous command was not a Q, q, T or t,
+ // assume the control point is coincident with the current point
+ controlX = x;
+ controlY = y;
+ } else {
+ // calculate reflection of previous control point
+ controlX = 2 * x - controlX;
+ controlY = 2 * y - controlY;
+ }
+
+ bounds = getBoundsOfCurve(
+ x,
+ y,
+ controlX,
+ controlY,
+ controlX,
+ controlY,
+ tempX,
+ tempY
+ );
+ x = tempX;
+ y = tempY;
+
+ break;
+
+ case "T":
+ tempX = current[1];
+ tempY = current[2];
+
+ if (previous[0].match(/[QqTt]/) === null) {
+ // If there is no previous command or if the previous command was not a Q, q, T or t,
+ // assume the control point is coincident with the current point
+ controlX = x;
+ controlY = y;
+ } else {
+ // calculate reflection of previous control point
+ controlX = 2 * x - controlX;
+ controlY = 2 * y - controlY;
+ }
+ bounds = getBoundsOfCurve(
+ x,
+ y,
+ controlX,
+ controlY,
+ controlX,
+ controlY,
+ tempX,
+ tempY
+ );
+ x = tempX;
+ y = tempY;
+ break;
+
+ case "na": // TODO: implement getBoundsOfArc
+ bounds = getBoundsOfArc(
+ x,
+ y,
+ current[1],
+ current[2],
+ current[3],
+ current[4],
+ current[5],
+ current[6] + x,
+ current[7] + y
+ );
+ x += current[6];
+ y += current[7];
+ break;
+
+ case "nA": // TODO: implement getBoundsOfArc absolute
+ bounds = getBoundsOfArc(
+ x,
+ y,
+ current[1],
+ current[2],
+ current[3],
+ current[4],
+ current[5],
+ current[6],
+ current[7]
+ );
+ x = current[6];
+ y = current[7];
+ break;
+
+ case "z":
+ case "Z":
+ x = subpathStartX;
+ y = subpathStartY;
+ break;
+ }
+ previous = current;
+ bounds.forEach(function(point) {
+ aX.push(point.x);
+ aY.push(point.y);
+ });
+ aX.push(x);
+ aY.push(y);
+ }
+
+ var minX = Math.min(...aX) || 0,
+ minY = Math.min(...aY) || 0,
+ maxX = Math.max(...aX) || 0,
+ maxY = Math.max(...aY) || 0,
+ deltaX = maxX - minX,
+ deltaY = maxY - minY;
+
+ return {
+ left: minX,
+ top: minY,
+ width: deltaX,
+ height: deltaY
+ };
+}
diff --git a/src/SVGPath.ts b/src/SVGPath.ts
index a8061e3..b87a6a5 100644
--- a/src/SVGPath.ts
+++ b/src/SVGPath.ts
@@ -1,4 +1,24 @@
-export function parsePathData(data) {
+import pathBounds from "./PathBounds";
+
+/**
+ * Useful SVG path tutorial on MDN
+ * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths
+ * @param data
+ */
+
+export function svgPathBoundingBox(svgpath: string) {
+ // TODO: access a cached array?
+ var ca = parsePathData(svgpath);
+ let bounds = pathBounds(ca);
+ return new createjs.Rectangle(
+ bounds.left,
+ bounds.top,
+ bounds.width,
+ bounds.height
+ );
+}
+
+export function parsePathData(data: string) {
if (!data) {
return [];
}
diff --git a/src/index.ts b/src/index.ts
index 8d42aa2..39ba6e8 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,5 @@
import "./GraphicsMixin";
+import copyEventListeners from "./utils/apply-shape-event-listeners";
export { default as Accessibility } from "./Accessibility";
export { default as Align } from "./Align";
@@ -16,8 +17,7 @@ export { default as Path, PathAlign, PathFit } from "./Path";
export { default as PathText } from "./PathText";
export { default as VerticalAlign } from "./VerticalAlign";
export { default as Word } from "./Word";
-
-import copyEventListeners from "./utils/apply-shape-event-listeners";
+export { svgPathBoundingBox } from "./SVGPath";
export const Util = {
copyEventListeners
diff --git a/tests/get-bounds.js b/tests/get-bounds.js
new file mode 100644
index 0000000..153d8dc
--- /dev/null
+++ b/tests/get-bounds.js
@@ -0,0 +1,47 @@
+describe("Text", function() {
+ var canvas;
+ var stage;
+ beforeEach(function() {
+ canvas = txtExamples.createHiDPICanvas(300, 300, 2);
+ document.body.appendChild(canvas);
+
+ stage = new createjs.Stage(canvas);
+ });
+
+ afterEach(function() {
+ txtExamples.clearExample();
+ });
+
+ it("getBounds of Glyph", function() {
+ var glyph = new txt.Glyph();
+ glyph.offset = 1063 / 2048;
+ glyph.path =
+ "M492 -246v226q-72 1 -136 28.5t-111 75t-74.5 111.5t-27.5 137v57l129 21v-78q0 -47 17 -88t47 -72t70 -49.5t86 -20.5v582q-66 24 -128.5 52.5t-111.5 72.5t-79 108t-30 158v27q0 72 27.5 135.5t74.5 111.5t111 76t136 29v184h102v-184q71 -1 134 -29.5t110 -76 t74.5 -111t27.5 -135.5v-37l-129 -21v58q0 46 -17 87t-46 71.5t-69 49.5t-85 21v-555q65 -25 129 -55t114.5 -75t81.5 -110.5t31 -160.5v-43q0 -73 -27.5 -137t-75.5 -112t-112 -75.5t-137 -27.5h-4v-226h-102zM821 375q0 57 -18 99.5t-48.5 74t-72 54.5t-88.5 42v-543 q47 0 88.5 18t72 49.5t48.5 73t18 89.5v43v0zM272 1075q0 -53 17 -92.5t47 -69.5t70 -53t86 -43v514q-46 -2 -86 -21t-70 -49.5t-47 -71.5t-17 -87v-27v0z";
+ var bounds = glyph.getBounds();
+ expect(bounds.width).toBeGreaterThan(0);
+ });
+
+ it("getBounds of Text", function() {
+ var text = new txt.Text({
+ text: "First poiretone",
+ font: "poiretone",
+ width: 400,
+ height: 400,
+ size: 100,
+ x: 0,
+ y: 0,
+ accessibilityPriority: 0
+ });
+
+ stage.addChild(text);
+
+ var bounds = text.getBounds();
+
+ expect(bounds).not.toBeNull();
+
+ expect(bounds.x).toBe(0);
+ expect(bounds.y).toBe(0);
+ expect(bounds.width).toBe(400);
+ expect(bounds.height).toBe(400);
+ });
+});
From 5a27ea8f8b68e776292049744358d801f4d3742a Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Wed, 12 Feb 2020 07:40:25 +1300
Subject: [PATCH 03/16] Added SVGPath comments from KineticJS
---
examples/Graphics/bounding_box.ts | 10 ++--
examples/Graphics/pathGraphics.ts | 2 +-
src/Glyph.ts | 2 +-
src/Graphics.ts | 3 ++
src/PathBounds.ts | 4 +-
src/SVGPath.ts | 84 +++++++++++++++++++------------
6 files changed, 65 insertions(+), 40 deletions(-)
diff --git a/examples/Graphics/bounding_box.ts b/examples/Graphics/bounding_box.ts
index 4041039..7d23829 100644
--- a/examples/Graphics/bounding_box.ts
+++ b/examples/Graphics/bounding_box.ts
@@ -1,11 +1,11 @@
import createHiDPICanvas from "../../lib/hidpi-canvas";
import svgPath from "../fixtures/svg-glyph";
export default function init() {
- let canvas = createHiDPICanvas(1000, 1000, 2);
+ const canvas = createHiDPICanvas(1000, 1000, 2);
document.body.appendChild(canvas);
- let stage = new createjs.Stage(canvas);
+ const stage = new createjs.Stage(canvas);
- var shape = new createjs.Shape();
+ const shape = new createjs.Shape();
shape.graphics.beginFill("#000");
shape.graphics.decodeSVGPath(svgPath);
@@ -13,9 +13,9 @@ export default function init() {
shape.y = 30;
stage.addChild(shape);
- var boundingBox = new createjs.Rectangle();
+ let boundingBox = new createjs.Rectangle();
boundingBox = txt.svgPathBoundingBox(svgPath);
- var boundaryLine = new createjs.Shape();
+ const boundaryLine = new createjs.Shape();
boundaryLine.y = 30;
boundaryLine.graphics
.beginStroke("#dd0000")
diff --git a/examples/Graphics/pathGraphics.ts b/examples/Graphics/pathGraphics.ts
index 97b8af3..ef88ac4 100755
--- a/examples/Graphics/pathGraphics.ts
+++ b/examples/Graphics/pathGraphics.ts
@@ -11,7 +11,7 @@ function createPathShape(path, strokeColor, fillColor = null) {
.beginStroke(strokeColor)
.decodeSVGPath(path);
- let bounds = txt.svgPathBoundingBox(path);
+ const bounds = txt.svgPathBoundingBox(path);
shape.setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
shape.graphics
diff --git a/src/Glyph.ts b/src/Glyph.ts
index ed39681..7b32e6f 100755
--- a/src/Glyph.ts
+++ b/src/Glyph.ts
@@ -55,7 +55,7 @@ export default class Glyph {
boundingLine() {
if (this._boundaryLine == null) {
this._boundaryLine = new createjs.Graphics();
- let bounds = this.getBounds();
+ const bounds = this.getBounds();
this._boundaryLine.append(
new createjs.Graphics.Rect(
bounds.x,
diff --git a/src/Graphics.ts b/src/Graphics.ts
index 8a61a93..885ac66 100644
--- a/src/Graphics.ts
+++ b/src/Graphics.ts
@@ -4,6 +4,9 @@ import { parsePathData, svgPathBoundingBox } from "./SVGPath";
export default class Graphics {
/**
* Build up createjs Graphics commands based on path data.
+ *
+ * Adapted from KineticJS
+ * @see https://github.com/ericdrowell/KineticJS/blob/master/src/plugins/Path.js#L41
*/
static init(target, svgpath: string) {
const ca = parsePathData(svgpath);
diff --git a/src/PathBounds.ts b/src/PathBounds.ts
index fe9f68d..22ac8a2 100644
--- a/src/PathBounds.ts
+++ b/src/PathBounds.ts
@@ -23,7 +23,7 @@ export default function pathBounds(path) {
tempY,
bounds;
- for (var i = 0, len = path.length; i < len; ++i) {
+ for (let i = 0, len = path.length; i < len; ++i) {
current = path[i].points.flat();
current.unshift(path[i].command);
@@ -326,7 +326,7 @@ export default function pathBounds(path) {
aY.push(y);
}
- var minX = Math.min(...aX) || 0,
+ const minX = Math.min(...aX) || 0,
minY = Math.min(...aY) || 0,
maxX = Math.max(...aX) || 0,
maxY = Math.max(...aY) || 0,
diff --git a/src/SVGPath.ts b/src/SVGPath.ts
index b87a6a5..cbb9697 100644
--- a/src/SVGPath.ts
+++ b/src/SVGPath.ts
@@ -8,8 +8,8 @@ import pathBounds from "./PathBounds";
export function svgPathBoundingBox(svgpath: string) {
// TODO: access a cached array?
- var ca = parsePathData(svgpath);
- let bounds = pathBounds(ca);
+ const ca = parsePathData(svgpath);
+ const bounds = pathBounds(ca);
return new createjs.Rectangle(
bounds.left,
bounds.top,
@@ -18,39 +18,51 @@ export function svgPathBoundingBox(svgpath: string) {
);
}
+/**
+ * Adapted from KineticJS
+ * @see https://github.com/ericdrowell/KineticJS/blob/master/src/plugins/Path.js#L210
+ */
export function parsePathData(data: string) {
if (!data) {
return [];
}
+ // command string
let cs = data;
+
+ // command chars
const cc = [
- "m",
- "M",
- "l",
- "L",
- "v",
- "V",
- "h",
- "H",
- "z",
- "Z",
- "c",
- "C",
- "q",
- "Q",
- "t",
- "T",
- "s",
- "S",
- "a",
- "A"
+ // Path Data Segment must begin with a moveTo
+ "m", //m (x y)+ Relative moveTo (subsequent points are treated as lineTo)
+ "M", //M (x y)+ Absolute moveTo (subsequent points are treated as lineTo)
+ "l", //l (x y)+ Relative lineTo
+ "L", //L (x y)+ Absolute LineTo
+ "v", //v (y)+ Relative vertical lineTo
+ "V", //V (y)+ Absolute vertical lineTo
+ "h", //h (x)+ Relative horizontal lineTo
+ "H", //H (x)+ Absolute horizontal lineTo
+ "z", //z (closepath)
+ "Z", //Z (closepath)
+ "c", //c (x1 y1 x2 y2 x y)+ Relative Bezier curve
+ "C", //C (x1 y1 x2 y2 x y)+ Absolute Bezier curve
+ "q", //q (x1 y1 x y)+ Relative Quadratic Bezier
+ "Q", //Q (x1 y1 x y)+ Absolute Quadratic Bezier
+ "t", //t (x y)+ Shorthand/Smooth Relative Quadratic Bezier
+ "T", //T (x y)+ Shorthand/Smooth Absolute Quadratic Bezier
+ "s", //s (x2 y2 x y)+ Shorthand/Smooth Relative Bezier curve
+ "S", //S (x2 y2 x y)+ Shorthand/Smooth Absolute Bezier curve
+ "a", //a (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ Relative Elliptical Arc
+ "A" //A (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ Absolute Elliptical Arc
];
+ // convert white spaces to commas
cs = cs.replace(new RegExp(" ", "g"), ",");
+ // create pipes so that we can split the data
for (let n = 0; n < cc.length; n++) {
cs = cs.replace(new RegExp(cc[n], "g"), "|" + cc[n]);
}
+ // create array
const arr = cs.split("|");
const ca = [];
+ // init context point
let cpx = 0;
let cpy = 0;
const arrLength = arr.length;
@@ -59,16 +71,20 @@ export function parsePathData(data: string) {
let str = arr[n];
let c = str.charAt(0);
str = str.slice(1);
+ // remove ,- for consistency
str = str.replace(new RegExp(",-", "g"), "-");
+ // add commas so that it's easy to split
str = str.replace(new RegExp("-", "g"), ",-");
str = str.replace(new RegExp("e,-", "g"), "e-");
- let p = str.split(",");
- if (p.length > 0 && p[0] === "") {
- p.shift();
+ const segments = str.split(",");
+ if (segments.length > 0 && segments[0] === "") {
+ segments.shift();
}
- const pLength = p.length;
- for (let i = 0; i < pLength; i++) {
- p[i] = parseFloat(p[i]);
+ let p = [];
+
+ // convert strings to floats
+ for (let i = 0; i < segments.length; i++) {
+ p[i] = parseFloat(segments[i]);
}
if (c === "z" || c === "Z") {
p = [true];
@@ -76,17 +92,21 @@ export function parsePathData(data: string) {
while (p.length > 0) {
if (isNaN(p[0])) {
+ // case for a trailing comma before next command
break;
}
let cmd = null;
let points = [];
const startX = cpx,
startY = cpy;
- let prevCmd, ctlPtx, ctlPty;
- let rx, ry, psi, fa, fs, x1, y1;
+ // Move var from within the switch to up here (jshint)
+ let prevCmd, ctlPtx, ctlPty; // Ss, Tt
+ let rx, ry, psi, fa, fs, x1, y1; // Aa
let dx, dy;
+ // convert l, H, h, V, and v to L
switch (c) {
+ // Note: Keep the lineTo's above the moveTo's in this switch
case "l":
cpx += p.shift();
cpy += p.shift();
@@ -99,7 +119,7 @@ export function parsePathData(data: string) {
cpy = p.shift();
points.push(cpx, cpy);
break;
-
+ // Note: lineTo handlers need to be above this point
case "m":
dx = p.shift();
dy = p.shift();
@@ -111,6 +131,7 @@ export function parsePathData(data: string) {
cmd = "M";
points.push(cpx, cpy);
c = "l";
+ // subsequent points are treated as relative lineTo
break;
case "M":
@@ -121,6 +142,7 @@ export function parsePathData(data: string) {
startPoint = [cpx, cpy];
}
points.push(cpx, cpy);
+ // subsequent points are treated as absolute lineTo
c = "L";
break;
From 1c1aee7d41a2c1a74ba130dbce2884d64894a460 Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Wed, 12 Feb 2020 19:41:53 +1300
Subject: [PATCH 04/16] Refactored boundary debug graphics building into it's
own fuction
---
src/Glyph.ts | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/src/Glyph.ts b/src/Glyph.ts
index 7b32e6f..b02c1a9 100755
--- a/src/Glyph.ts
+++ b/src/Glyph.ts
@@ -54,21 +54,26 @@ export default class Glyph {
boundingLine() {
if (this._boundaryLine == null) {
- this._boundaryLine = new createjs.Graphics();
const bounds = this.getBounds();
- this._boundaryLine.append(
- new createjs.Graphics.Rect(
- bounds.x,
- bounds.y,
- bounds.width,
- bounds.height
- )
- );
- this._boundaryLine.append(new createjs.Graphics.StrokeDash([10, 4]));
- this._boundaryLine.append(new createjs.Graphics.Stroke("#FF00FF", true));
+ this._boundaryLine = Glyph.buildBoundaryGraphics(bounds);
}
}
+ static buildBoundaryGraphics(bounds: createjs.Rectangle): createjs.Graphics {
+ const boundary = new createjs.Graphics();
+ boundary.append(
+ new createjs.Graphics.Rect(
+ bounds.x,
+ bounds.y,
+ bounds.width,
+ bounds.height
+ )
+ );
+ boundary.append(new createjs.Graphics.StrokeDash([10, 4]));
+ boundary.append(new createjs.Graphics.Stroke("#FF00FF", true));
+ return boundary;
+ }
+
draw(ctx: CanvasRenderingContext2D): boolean {
this._graphic.draw(ctx);
if (Glyph.debug) {
From 7edcd70ad698f15929bf36409806cb552167a125 Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Wed, 26 Feb 2020 06:58:43 +1300
Subject: [PATCH 05/16] Fix Glyph debug static
---
src/Glyph.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Glyph.ts b/src/Glyph.ts
index b02c1a9..ebf80d3 100755
--- a/src/Glyph.ts
+++ b/src/Glyph.ts
@@ -16,7 +16,7 @@ export default class Glyph {
_stroke: createjs.Graphics.Stroke;
_strokeStyle: createjs.Graphics.StrokeStyle;
- static debug: false;
+ static debug: boolean = false;
graphic() {
if (this._graphic == null) {
From c78acaa419f7e3f79f896d3d935aebc350ab2a9b Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Wed, 26 Feb 2020 06:59:01 +1300
Subject: [PATCH 06/16] Added bounding_box example
---
examples/CharacterText/bounding_box.ts | 28 ++++++++++++++++++++++++++
examples/character-text.ts | 2 ++
2 files changed, 30 insertions(+)
create mode 100644 examples/CharacterText/bounding_box.ts
diff --git a/examples/CharacterText/bounding_box.ts b/examples/CharacterText/bounding_box.ts
new file mode 100644
index 0000000..e5057fa
--- /dev/null
+++ b/examples/CharacterText/bounding_box.ts
@@ -0,0 +1,28 @@
+import createHiDPICanvas from "../../lib/hidpi-canvas";
+export default function init() {
+ let canvas = createHiDPICanvas(500, 500, 2);
+ document.body.appendChild(canvas);
+ let stage = new createjs.Stage(canvas);
+
+ let charText = new txt.CharacterText({
+ text: "The fox\n jumped over...",
+ font: "raleway",
+ tracking: 20,
+ minSize: 70,
+ width: 500,
+ height: 500,
+ size: 120,
+ x: 100,
+ y: 100,
+ debug: true
+ });
+ stage.addChild(charText);
+
+ charText.layout();
+
+ console.log(charText.getBounds());
+
+ stage.update();
+
+ return stage;
+}
diff --git a/examples/character-text.ts b/examples/character-text.ts
index 72e0888..6250b82 100644
--- a/examples/character-text.ts
+++ b/examples/character-text.ts
@@ -4,6 +4,7 @@ import autosize_expand from "./CharacterText/autosize_expand";
import autosize_reduce from "./CharacterText/autosize_reduce";
import autosize_reduce_expand from "./CharacterText/autosize_reduce_expand";
import autosize_reduce_layout from "./CharacterText/autosize_reduce_layout";
+import bounding_box from "./CharacterText/bounding_box";
import cache from "./CharacterText/cache";
import character_case from "./CharacterText/case";
import child_events from "./CharacterText/child_events";
@@ -39,6 +40,7 @@ export const visual = {
autosize_reduce,
autosize_reduce_expand,
autosize_reduce_layout,
+ bounding_box,
case: character_case,
column,
ligatures,
From 97753b3fcd4b68ada73462f228bc91093695c227 Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Wed, 26 Feb 2020 16:27:25 +1300
Subject: [PATCH 07/16] Split graphics examples into visual / non-visual
---
examples/character-text.ts | 2 +-
examples/graphics.ts | 12 +++++++++++-
examples/index.ts | 4 ++--
3 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/examples/character-text.ts b/examples/character-text.ts
index 6250b82..371089a 100644
--- a/examples/character-text.ts
+++ b/examples/character-text.ts
@@ -40,7 +40,6 @@ export const visual = {
autosize_reduce,
autosize_reduce_expand,
autosize_reduce_layout,
- bounding_box,
case: character_case,
column,
ligatures,
@@ -66,6 +65,7 @@ export const visual = {
export const nonVisual = {
accessibility,
+ bounding_box,
cache,
complete,
child_events,
diff --git a/examples/graphics.ts b/examples/graphics.ts
index 2ae08e5..f74ef24 100644
--- a/examples/graphics.ts
+++ b/examples/graphics.ts
@@ -3,4 +3,14 @@ import pathGraphics2 from "./Graphics/pathGraphics2";
import pathGraphics3 from "./Graphics/pathGraphics3";
import bounding_box from "./Graphics/bounding_box";
-export default { pathGraphics, pathGraphics2, pathGraphics3, bounding_box };
+export const visual = {
+ pathGraphics,
+ pathGraphics2,
+ pathGraphics3
+};
+
+export const nonVisual = {
+ bounding_box
+};
+
+export default { ...visual, ...nonVisual };
diff --git a/examples/index.ts b/examples/index.ts
index 061b8db..30cd281 100644
--- a/examples/index.ts
+++ b/examples/index.ts
@@ -5,7 +5,7 @@ txt.FontLoader.path = "../font/";
import { visual as CharacterTextVisual } from "./character-text";
import { visual as TextVisual } from "./text";
import { visual as PathTextVisual } from "./path-text";
-import Graphics from "./graphics";
+import { visual as GraphicsVisual } from "./graphics";
import { nonVisual as CharacterTextNonVisual } from "./character-text";
import { nonVisual as TextNonVisual } from "./text";
@@ -16,7 +16,7 @@ export const visualExamples = {
CharacterText: CharacterTextVisual,
Text: TextVisual,
PathText: PathTextVisual,
- Graphics
+ Graphics: GraphicsVisual
};
export const nonVisualExamples = {
From db0e439be0c59fd22d15beba2b92145139616172 Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Wed, 26 Feb 2020 16:28:12 +1300
Subject: [PATCH 08/16] Remove bounds rendering from pathGraphics
---
examples/Graphics/pathGraphics.ts | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/examples/Graphics/pathGraphics.ts b/examples/Graphics/pathGraphics.ts
index ef88ac4..98eb1d9 100755
--- a/examples/Graphics/pathGraphics.ts
+++ b/examples/Graphics/pathGraphics.ts
@@ -11,16 +11,6 @@ function createPathShape(path, strokeColor, fillColor = null) {
.beginStroke(strokeColor)
.decodeSVGPath(path);
- const bounds = txt.svgPathBoundingBox(path);
- shape.setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
-
- shape.graphics
- .endFill()
- .setStrokeStyle(1)
- .setStrokeDash([20, 10], 0)
- .beginStroke("#93F")
- .drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
-
return shape;
}
From 22fb0170467861290ef7c22591490e95b6d3e2b5 Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Wed, 4 Mar 2020 16:48:17 +1300
Subject: [PATCH 09/16] Eslint fixes
---
examples/CharacterText/bounding_box.ts | 6 +++---
src/Glyph.ts | 2 +-
src/Graphics.ts | 2 +-
src/PathBounds.ts | 6 +++---
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/examples/CharacterText/bounding_box.ts b/examples/CharacterText/bounding_box.ts
index e5057fa..6e95ac1 100644
--- a/examples/CharacterText/bounding_box.ts
+++ b/examples/CharacterText/bounding_box.ts
@@ -1,10 +1,10 @@
import createHiDPICanvas from "../../lib/hidpi-canvas";
export default function init() {
- let canvas = createHiDPICanvas(500, 500, 2);
+ const canvas = createHiDPICanvas(500, 500, 2);
document.body.appendChild(canvas);
- let stage = new createjs.Stage(canvas);
+ const stage = new createjs.Stage(canvas);
- let charText = new txt.CharacterText({
+ const charText = new txt.CharacterText({
text: "The fox\n jumped over...",
font: "raleway",
tracking: 20,
diff --git a/src/Glyph.ts b/src/Glyph.ts
index ebf80d3..df1d77d 100755
--- a/src/Glyph.ts
+++ b/src/Glyph.ts
@@ -16,7 +16,7 @@ export default class Glyph {
_stroke: createjs.Graphics.Stroke;
_strokeStyle: createjs.Graphics.StrokeStyle;
- static debug: boolean = false;
+ static debug = false;
graphic() {
if (this._graphic == null) {
diff --git a/src/Graphics.ts b/src/Graphics.ts
index 885ac66..4f14e52 100644
--- a/src/Graphics.ts
+++ b/src/Graphics.ts
@@ -1,5 +1,5 @@
import SVGArc from "./SVGArc";
-import { parsePathData, svgPathBoundingBox } from "./SVGPath";
+import { parsePathData } from "./SVGPath";
export default class Graphics {
/**
diff --git a/src/PathBounds.ts b/src/PathBounds.ts
index 22ac8a2..9c54acf 100644
--- a/src/PathBounds.ts
+++ b/src/PathBounds.ts
@@ -9,9 +9,9 @@ function getBoundsOfArc(fx, fy, rx, ry, rot, large, sweep, tx, ty) {
}
export default function pathBounds(path) {
- let aX = [],
- aY = [],
- current, // current instruction
+ const aX = [],
+ aY = [];
+ let current, // current instruction
previous = null,
subpathStartX = 0,
subpathStartY = 0,
From c00b50a2238f30110b06f878d13a1180e6cb3e48 Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Wed, 4 Mar 2020 21:17:32 +1300
Subject: [PATCH 10/16] Minor renaming for readability
---
src/Character.ts | 6 +++---
src/CharacterText.ts | 9 ++++-----
2 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/src/Character.ts b/src/Character.ts
index 6e5be03..7e9261a 100644
--- a/src/Character.ts
+++ b/src/Character.ts
@@ -109,8 +109,8 @@ export default class Character extends createjs.Shape {
(this._font.ascent - this._font.descent) * this.scaleX;
this.measuredWidth = this.scaleX * this._glyph.offset * this._font.units;
- const ha = new createjs.Shape();
- ha.graphics
+ const hitArea = new createjs.Shape();
+ hitArea.graphics
.beginFill("#000")
.drawRect(
0,
@@ -118,7 +118,7 @@ export default class Character extends createjs.Shape {
this._glyph.offset * this._font.units,
this._font.ascent - this._font.descent
);
- this.hitArea = ha;
+ this.hitArea = hitArea;
this._glyph.boundingLine();
}
diff --git a/src/CharacterText.ts b/src/CharacterText.ts
index cd510c6..11c8944 100644
--- a/src/CharacterText.ts
+++ b/src/CharacterText.ts
@@ -300,7 +300,6 @@ export default class CharacterText extends TextContainer {
*/
characterLayout(): boolean {
//char layout
- const len = this.text.length;
let char: Character;
const defaultStyle: Style = {
size: this.size,
@@ -322,9 +321,9 @@ export default class CharacterText extends TextContainer {
this.lines.push(currentLine);
this.block.addChild(currentLine);
- // loop over characters
- // place into lines
- for (let i = 0; i < len; i++) {
+ // loop over characters, and place into lines
+ for (let i = 0; i < this.text.length; i++) {
+ // apply custom character styles
if (this.style !== null && this.style[i] !== undefined) {
currentStyle = this.style[i];
// make sure style contains properties needed.
@@ -350,7 +349,7 @@ export default class CharacterText extends TextContainer {
// new line has no character
if (this.text.charAt(i) == "\n" || this.text.charAt(i) == "\r") {
//only if not last char
- if (i < len - 1) {
+ if (i < this.text.length - 1) {
if (firstLine === true) {
vPosition = currentStyle.size;
currentLine.measuredHeight = currentStyle.size;
From 9fe748dad9dd74dfb30d80865f3009b3cab9cb3d Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Thu, 9 Jul 2020 21:25:53 +1200
Subject: [PATCH 11/16] Fix type issues
---
examples/CharacterText/bounding_box.ts | 3 ++-
examples/Graphics/bounding_box.ts | 2 ++
src/types/createjs.d.ts | 8 ++++++++
3 files changed, 12 insertions(+), 1 deletion(-)
create mode 100644 src/types/createjs.d.ts
diff --git a/examples/CharacterText/bounding_box.ts b/examples/CharacterText/bounding_box.ts
index 6e95ac1..0804d00 100644
--- a/examples/CharacterText/bounding_box.ts
+++ b/examples/CharacterText/bounding_box.ts
@@ -1,3 +1,4 @@
+import * as txt from "txt";
import createHiDPICanvas from "../../lib/hidpi-canvas";
export default function init() {
const canvas = createHiDPICanvas(500, 500, 2);
@@ -14,7 +15,7 @@ export default function init() {
size: 120,
x: 100,
y: 100,
- debug: true
+ debug: true,
});
stage.addChild(charText);
diff --git a/examples/Graphics/bounding_box.ts b/examples/Graphics/bounding_box.ts
index 7d23829..2723c8e 100644
--- a/examples/Graphics/bounding_box.ts
+++ b/examples/Graphics/bounding_box.ts
@@ -1,5 +1,7 @@
+import * as txt from "txt";
import createHiDPICanvas from "../../lib/hidpi-canvas";
import svgPath from "../fixtures/svg-glyph";
+
export default function init() {
const canvas = createHiDPICanvas(1000, 1000, 2);
document.body.appendChild(canvas);
diff --git a/src/types/createjs.d.ts b/src/types/createjs.d.ts
new file mode 100644
index 0000000..c03b55c
--- /dev/null
+++ b/src/types/createjs.d.ts
@@ -0,0 +1,8 @@
+// TODO: get this addded into the @types/easeljs package
+declare namespace createjs {
+ namespace Graphics {
+ class StrokeDash {
+ constructor(segments: Array, offset?: number);
+ }
+ }
+}
From c609e0d307b7e4da6072407624e510c3f2d2aa70 Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Thu, 9 Jul 2020 21:26:20 +1200
Subject: [PATCH 12/16] Resize bounding box example canvas size
---
examples/Graphics/bounding_box.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/Graphics/bounding_box.ts b/examples/Graphics/bounding_box.ts
index 2723c8e..16e35c7 100644
--- a/examples/Graphics/bounding_box.ts
+++ b/examples/Graphics/bounding_box.ts
@@ -3,7 +3,7 @@ import createHiDPICanvas from "../../lib/hidpi-canvas";
import svgPath from "../fixtures/svg-glyph";
export default function init() {
- const canvas = createHiDPICanvas(1000, 1000, 2);
+ const canvas = createHiDPICanvas(500, 300, 2);
document.body.appendChild(canvas);
const stage = new createjs.Stage(canvas);
From add94521b5aefe89870bd1a3528bd2f74b772218 Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Fri, 10 Jul 2020 15:05:13 +1200
Subject: [PATCH 13/16] Convert get-bounds test to typescript
---
tests/{get-bounds.js => get-bounds.ts} | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
rename tests/{get-bounds.js => get-bounds.ts} (82%)
diff --git a/tests/get-bounds.js b/tests/get-bounds.ts
similarity index 82%
rename from tests/get-bounds.js
rename to tests/get-bounds.ts
index 153d8dc..5f428c3 100644
--- a/tests/get-bounds.js
+++ b/tests/get-bounds.ts
@@ -1,6 +1,9 @@
+import * as txt from "txt";
+import * as txtExamples from "examples";
+import { removeCanvas } from "./helpers";
describe("Text", function() {
- var canvas;
- var stage;
+ let canvas;
+ let stage;
beforeEach(function() {
canvas = txtExamples.createHiDPICanvas(300, 300, 2);
document.body.appendChild(canvas);
@@ -9,20 +12,20 @@ describe("Text", function() {
});
afterEach(function() {
- txtExamples.clearExample();
+ removeCanvas();
});
it("getBounds of Glyph", function() {
- var glyph = new txt.Glyph();
+ const glyph = new txt.Glyph();
glyph.offset = 1063 / 2048;
glyph.path =
"M492 -246v226q-72 1 -136 28.5t-111 75t-74.5 111.5t-27.5 137v57l129 21v-78q0 -47 17 -88t47 -72t70 -49.5t86 -20.5v582q-66 24 -128.5 52.5t-111.5 72.5t-79 108t-30 158v27q0 72 27.5 135.5t74.5 111.5t111 76t136 29v184h102v-184q71 -1 134 -29.5t110 -76 t74.5 -111t27.5 -135.5v-37l-129 -21v58q0 46 -17 87t-46 71.5t-69 49.5t-85 21v-555q65 -25 129 -55t114.5 -75t81.5 -110.5t31 -160.5v-43q0 -73 -27.5 -137t-75.5 -112t-112 -75.5t-137 -27.5h-4v-226h-102zM821 375q0 57 -18 99.5t-48.5 74t-72 54.5t-88.5 42v-543 q47 0 88.5 18t72 49.5t48.5 73t18 89.5v43v0zM272 1075q0 -53 17 -92.5t47 -69.5t70 -53t86 -43v514q-46 -2 -86 -21t-70 -49.5t-47 -71.5t-17 -87v-27v0z";
- var bounds = glyph.getBounds();
+ const bounds = glyph.getBounds();
expect(bounds.width).toBeGreaterThan(0);
});
it("getBounds of Text", function() {
- var text = new txt.Text({
+ const text = new txt.Text({
text: "First poiretone",
font: "poiretone",
width: 400,
@@ -35,7 +38,7 @@ describe("Text", function() {
stage.addChild(text);
- var bounds = text.getBounds();
+ const bounds = text.getBounds();
expect(bounds).not.toBeNull();
From 4236cee8dda6d374bf7e1dccaaf06cae4a21d462 Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Fri, 10 Jul 2020 15:11:16 +1200
Subject: [PATCH 14/16] Fix headless tests output
---
testem.js | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/testem.js b/testem.js
index 831cc3a..bddfe85 100644
--- a/testem.js
+++ b/testem.js
@@ -12,17 +12,17 @@ let serve_files = [
{ src: coverageServer.clientFile },
{
src:
- "node_modules/@recreatejs/jasmine-pixelmatch/dist/jasmine-pixelmatch.js"
+ "node_modules/@recreatejs/jasmine-pixelmatch/dist/jasmine-pixelmatch.js",
},
{ src: "dist/easeljs.js" },
{ src: "dist/pathseg.js" },
{ src: "dist/txt.instrumented.umd.js" },
{ src: "dist/examples.umd.js" },
- { src: "dist/tests.umd.js" }
+ { src: "dist/tests.umd.js" },
];
-if (!process.env.HEADLESS) {
- serve_files.push({ src: "!dist/esnext/tests/_headless.js" });
+if (process.env.HEADLESS) {
+ serve_files.push({ src: "dist/esnext/tests/_headless.js" });
}
module.exports = {
@@ -30,14 +30,14 @@ module.exports = {
launch_in_ci: ["Chrome"],
browser_args: {
Chrome: chromeArgs,
- Firefox: firefoxArgs
+ Firefox: firefoxArgs,
},
test_page: "testem.mustache",
src_files: ["src/**/*.ts", "examples/**/*.ts"],
serve_files,
css_files: [],
routes: {
- "/images": "images"
+ "/images": "images",
},
proxies: coverageServer.proxies,
before_tests: function(config, data, callback) {
@@ -45,5 +45,5 @@ module.exports = {
},
after_tests: function(config, data, callback) {
coverageServer.shutdownCoverageServer(callback);
- }
+ },
};
From 95a238eebd455b39a2fc907ec71a321b9067b09d Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Fri, 10 Jul 2020 22:41:43 +1200
Subject: [PATCH 15/16] Added bounding box example link
---
index.html | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/index.html b/index.html
index 5dcc743..a7ac084 100644
--- a/index.html
+++ b/index.html
@@ -250,7 +250,9 @@ CharacterText
Fit - singleLine autoReduce + autoExpand
-
+
+ Bounding box
+
From 0bb6175b3c8c84c07accd261f8f58fd6ec787d2b Mon Sep 17 00:00:00 2001
From: Jeremy Shipman
Date: Fri, 10 Jul 2020 22:43:00 +1200
Subject: [PATCH 16/16] Factored out alignment helper functions
---
src/Align.ts | 24 ++++++++++++++++++++++++
src/CharacterText.ts | 20 ++++----------------
src/Text.ts | 34 +++++++++++-----------------------
3 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/src/Align.ts b/src/Align.ts
index 833aaf1..20640d2 100644
--- a/src/Align.ts
+++ b/src/Align.ts
@@ -20,3 +20,27 @@ enum Align {
}
export default Align;
+
+export function topAligned(alignment: number): boolean {
+ return (
+ alignment === Align.TOP_LEFT ||
+ alignment === Align.TOP_CENTER ||
+ alignment === Align.TOP_RIGHT
+ );
+}
+
+export function middleAligned(alignment: number): boolean {
+ return (
+ alignment === Align.MIDDLE_LEFT ||
+ alignment === Align.MIDDLE_CENTER ||
+ alignment === Align.MIDDLE_RIGHT
+ );
+}
+
+export function bottomAligned(alignment: number): boolean {
+ return (
+ alignment === Align.BOTTOM_LEFT ||
+ alignment === Align.BOTTOM_CENTER ||
+ alignment === Align.BOTTOM_RIGHT
+ );
+}
diff --git a/src/CharacterText.ts b/src/CharacterText.ts
index 11c8944..bc8517b 100644
--- a/src/CharacterText.ts
+++ b/src/CharacterText.ts
@@ -1,5 +1,5 @@
import TextContainer from "./TextContainer";
-import Align from "./Align";
+import Align, { topAligned, middleAligned, bottomAligned } from "./Align";
import FontLoader from "./FontLoader";
import { ConstructObj, Style } from "./Interfaces";
import Font from "./Font";
@@ -577,11 +577,7 @@ export default class CharacterText extends TextContainer {
}
//TOP ALIGNED
- if (
- this.align === a.TOP_LEFT ||
- this.align === a.TOP_CENTER ||
- this.align === a.TOP_RIGHT
- ) {
+ if (topAligned(this.align)) {
if (fnt.top == 0) {
this.block.y = (this.lines[0].measuredHeight * fnt.ascent) / fnt.units;
} else {
@@ -591,22 +587,14 @@ export default class CharacterText extends TextContainer {
}
//MIDDLE ALIGNED
- } else if (
- this.align === a.MIDDLE_LEFT ||
- this.align === a.MIDDLE_CENTER ||
- this.align === a.MIDDLE_RIGHT
- ) {
+ } else if (middleAligned(this.align)) {
this.block.y =
this.lines[0].measuredHeight +
(this.height - measuredHeight) / 2 +
(this.lines[0].measuredHeight * fnt.middle) / fnt.units;
//BOTTOM ALIGNED
- } else if (
- this.align === a.BOTTOM_LEFT ||
- this.align === a.BOTTOM_CENTER ||
- this.align === a.BOTTOM_RIGHT
- ) {
+ } else if (bottomAligned(this.align)) {
this.block.y =
this.height -
this.lines[this.lines.length - 1].y +
diff --git a/src/Text.ts b/src/Text.ts
index 5de61e6..8344e89 100644
--- a/src/Text.ts
+++ b/src/Text.ts
@@ -1,5 +1,5 @@
import TextContainer from "./TextContainer";
-import Align from "./Align";
+import Align, { topAligned, middleAligned, bottomAligned } from "./Align";
import FontLoader from "./FontLoader";
import Word from "./Word";
import Line from "./Line";
@@ -451,7 +451,7 @@ export default class Text extends TextContainer {
// place into text
let measuredHeight = 0;
let line;
- const a = Align;
+
const fnt: Font = FontLoader.getFont(this.font);
const len = this.lines.length;
@@ -471,54 +471,42 @@ export default class Text extends TextContainer {
}
measuredHeight += line.measuredHeight;
- if (this.align === a.TOP_CENTER) {
+ if (this.align === Align.TOP_CENTER) {
//move to center
line.x = (this.width - line.measuredWidth) / 2;
- } else if (this.align === a.TOP_RIGHT) {
+ } else if (this.align === Align.TOP_RIGHT) {
//move to right
line.x = this.width - line.measuredWidth;
- } else if (this.align === a.MIDDLE_CENTER) {
+ } else if (this.align === Align.MIDDLE_CENTER) {
//move to center
line.x = (this.width - line.measuredWidth) / 2;
- } else if (this.align === a.MIDDLE_RIGHT) {
+ } else if (this.align === Align.MIDDLE_RIGHT) {
//move to right
line.x = this.width - line.measuredWidth;
- } else if (this.align === a.BOTTOM_CENTER) {
+ } else if (this.align === Align.BOTTOM_CENTER) {
//move to center
line.x = (this.width - line.measuredWidth) / 2;
- } else if (this.align === a.BOTTOM_RIGHT) {
+ } else if (this.align === Align.BOTTOM_RIGHT) {
//move to right
line.x = this.width - line.measuredWidth;
}
}
//TOP ALIGNED
- if (
- this.align === a.TOP_LEFT ||
- this.align === a.TOP_CENTER ||
- this.align === a.TOP_RIGHT
- ) {
+ if (topAligned(this.align)) {
this.block.y =
(this.lines[0].measuredHeight * fnt.ascent) / fnt.units +
(this.lines[0].measuredHeight * fnt.top) / fnt.units;
//MIDDLE ALIGNED
- } else if (
- this.align === a.MIDDLE_LEFT ||
- this.align === a.MIDDLE_CENTER ||
- this.align === a.MIDDLE_RIGHT
- ) {
+ } else if (middleAligned(this.align)) {
this.block.y =
this.lines[0].measuredHeight +
(this.height - measuredHeight) / 2 +
(this.lines[0].measuredHeight * fnt.middle) / fnt.units;
//BOTTOM ALIGNED
- } else if (
- this.align === a.BOTTOM_LEFT ||
- this.align === a.BOTTOM_CENTER ||
- this.align === a.BOTTOM_RIGHT
- ) {
+ } else if (bottomAligned(this.align)) {
this.block.y =
this.height -
this.lines[this.lines.length - 1].y +