From c64d8283d4feaf93db8b15751aad5f90b541975c Mon Sep 17 00:00:00 2001 From: k1w1 Date: Sun, 17 Jul 2022 09:06:40 -0700 Subject: [PATCH 1/2] Fix a problem with ellipse drawing if at translation is applied. --- context.js | 10 ++++++++-- test/index.js | 2 ++ test/rendering.test.js | 2 ++ test/tests/ellipse2.js | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 test/tests/ellipse2.js diff --git a/context.js b/context.js index d0de57b..a82dc5a 100644 --- a/context.js +++ b/context.js @@ -1071,8 +1071,14 @@ export default (function () { } else { largeArcFlag = diff > Math.PI ? 1 : 0; } - - this.lineTo(startX / scaleX, startY / scaleY); + + // Transform is already applied, so temporarily remove since lineTo + // will apply it again. + var currentTransform = this.__transformMatrix; + this.resetTransform(); + this.lineTo(startX, startY); + this.__transformMatrix = currentTransform; + this.__addPathCommand(format("A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}", { rx:radiusX, diff --git a/test/index.js b/test/index.js index 8bdf8ee..1e9ace3 100644 --- a/test/index.js +++ b/test/index.js @@ -4,6 +4,7 @@ import arcTo from './tests/arcTo' import arcTo2 from './tests/arcTo2' import emptyArc from './tests/emptyArc' import ellipse from './tests/ellipse' +import ellipse2 from './tests/ellipse2' import fillstyle from './tests/fillstyle' import globalAlpha from './tests/globalalpha' import gradient from './tests/gradient' @@ -25,6 +26,7 @@ const tests = [ arcTo2, emptyArc, ellipse, + ellipse2, fillstyle, globalAlpha, gradient, diff --git a/test/rendering.test.js b/test/rendering.test.js index a2fe1da..4f01cfa 100644 --- a/test/rendering.test.js +++ b/test/rendering.test.js @@ -5,6 +5,7 @@ import arcTo from './tests/arcTo' import arcTo2 from './tests/arcTo2' import emptyArc from './tests/emptyArc' import ellipse from './tests/ellipse' +import ellipse2 from './tests/ellipse2' import fillstyle from './tests/fillstyle' import globalAlpha from './tests/globalalpha' import gradient from './tests/gradient' @@ -26,6 +27,7 @@ const tests = { arcTo2, emptyArc, ellipse, + ellipse2, fillstyle, globalAlpha, gradient, diff --git a/test/tests/ellipse2.js b/test/tests/ellipse2.js new file mode 100644 index 0000000..e8472a6 --- /dev/null +++ b/test/tests/ellipse2.js @@ -0,0 +1,32 @@ + +export default function ellipse2(ctx) { + // Draw a cylinder using ellipses and lines. + var w = 100, h = 100, rx = 50, ry = 10; + var scaleX = 1.5, scaleY = 2.5; + + ctx.scale(scaleX, scaleY); + ctx.translate(100, 75); + + ctx.beginPath(); + ctx.moveTo(-w / 2, -h / 2 + ry); + // upper arc top + ctx.ellipse(0, -h / 2 + ry, rx, ry, Math.PI, 0, Math.PI, 0); + ctx.moveTo(-w / 2, -h / 2 + ry); + // upper arc bottom + ctx.ellipse(0, -h / 2 + ry, rx, ry, Math.PI, 0, Math.PI, 1); + ctx.moveTo(-w / 2, -h / 2 + ry); + // left line + ctx.lineTo(-w / 2, + h / 2 - ry); + // lower arc + ctx.ellipse(0, h / 2 - ry, rx, ry, Math.PI, 0, Math.PI, 1); + // right line + ctx.lineTo(w / 2, -h / 2 + ry); + ctx.moveTo(-w / 2, -h / 2 + ry); + ctx.closePath(); + + // Remove scale before stroking because the SVG conversion is not correctly + // scaling the stroke as well. Without this the pixel differences are too + // high. + ctx.scale(1 / scaleX, 1 / scaleY); + ctx.stroke(); +}; \ No newline at end of file From 6e7449a6395cd06881138afe9f3afdfc3c96dc84 Mon Sep 17 00:00:00 2001 From: k1w1 Date: Sun, 17 Jul 2022 09:55:39 -0700 Subject: [PATCH 2/2] Fixed problem when rotation is applied --- context.js | 32 ++++++++++++++++++++++++++------ test/tests/ellipse2.js | 7 ++++--- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/context.js b/context.js index a82dc5a..50e067b 100644 --- a/context.js +++ b/context.js @@ -1038,12 +1038,13 @@ export default (function () { return; } - x = this.__matrixTransform(x, y).x; - y = this.__matrixTransform(x, y).y; - var scaleX = Math.hypot(this.__transformMatrix.a, this.__transformMatrix.b); - var scaleY = Math.hypot(this.__transformMatrix.c, this.__transformMatrix.d); - radiusX = radiusX * scaleX; - radiusY = radiusY * scaleY; + var transformedCenter = this.__matrixTransform(x, y); + x = transformedCenter.x; + y = transformedCenter.y; + var scale = this.__getTransformScale(); + radiusX = radiusX * scale.x; + radiusY = radiusY * scale.y; + rotation = rotation + this.__getTransformRotation() startAngle = startAngle % (2*Math.PI); endAngle = endAngle % (2*Math.PI); @@ -1338,6 +1339,25 @@ export default (function () { return new DOMPoint(x, y).matrixTransform(this.__transformMatrix) } + /** + * + * @returns The scale component of the transform matrix as {x,y}. + */ + Context.prototype.__getTransformScale = function() { + return { + x: Math.hypot(this.__transformMatrix.a, this.__transformMatrix.b), + y: Math.hypot(this.__transformMatrix.c, this.__transformMatrix.d) + }; + } + + /** + * + * @returns The rotation component of the transform matrix in radians. + */ + Context.prototype.__getTransformRotation = function() { + return Math.atan2(this.__transformMatrix.b, this.__transformMatrix.a); + } + /** * * @param {*} sx The x-axis coordinate of the top-left corner of the rectangle from which the ImageData will be extracted. diff --git a/test/tests/ellipse2.js b/test/tests/ellipse2.js index e8472a6..73feaaa 100644 --- a/test/tests/ellipse2.js +++ b/test/tests/ellipse2.js @@ -2,10 +2,11 @@ export default function ellipse2(ctx) { // Draw a cylinder using ellipses and lines. var w = 100, h = 100, rx = 50, ry = 10; - var scaleX = 1.5, scaleY = 2.5; + var scaleX = 1.5, scaleY = 1.2; + ctx.rotate(Math.PI / 10); ctx.scale(scaleX, scaleY); - ctx.translate(100, 75); + ctx.translate(200, 25); ctx.beginPath(); ctx.moveTo(-w / 2, -h / 2 + ry); @@ -27,6 +28,6 @@ export default function ellipse2(ctx) { // Remove scale before stroking because the SVG conversion is not correctly // scaling the stroke as well. Without this the pixel differences are too // high. - ctx.scale(1 / scaleX, 1 / scaleY); + ctx.resetTransform(); ctx.stroke(); }; \ No newline at end of file