From f4b7ece3575737b08eefb7d17a037f1c785066e7 Mon Sep 17 00:00:00 2001 From: k1w1 Date: Thu, 14 Jul 2022 20:36:39 -0700 Subject: [PATCH 1/2] Add ellipse function Based on code in this PR https://github.com/gliffy/canvas2svg/pull/36 --- context.js | 41 +++++++++++++++++++++++++++++++++++++++++ test/index.js | 2 ++ test/rendering.test.js | 2 ++ test/tests/ellipse.js | 28 ++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 test/tests/ellipse.js diff --git a/context.js b/context.js index 45cfcb4..875d2e9 100644 --- a/context.js +++ b/context.js @@ -1030,6 +1030,47 @@ export default (function () { this.__currentPosition = {x: endX, y: endY}; }; + /** + * Ellipse command! + */ + Context.prototype.ellipse = function(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterClockwise) { + if (startAngle === endAngle) { + return; + } + startAngle = startAngle % (2*Math.PI); + endAngle = endAngle % (2*Math.PI); + if(startAngle === endAngle) { + endAngle = ((endAngle + (2*Math.PI)) - 0.001 * (counterClockwise ? -1 : 1)) % (2*Math.PI); + } + var endX = x + Math.cos(-rotation) * radiusX * Math.cos(endAngle) + + Math.sin(-rotation) * radiusY * Math.sin(endAngle), + endY = y - Math.sin(-rotation) * radiusX * Math.cos(endAngle) + + Math.cos(-rotation) * radiusY * Math.sin(endAngle), + startX = x + Math.cos(-rotation) * radiusX * Math.cos(startAngle) + + Math.sin(-rotation) * radiusY * Math.sin(startAngle), + startY = y - Math.sin(-rotation) * radiusX * Math.cos(startAngle) + + Math.cos(-rotation) * radiusY * Math.sin(startAngle), + sweepFlag = counterClockwise ? 0 : 1, + largeArcFlag = 0, + diff = endAngle - startAngle; + + if(diff < 0) { + diff += 2*Math.PI; + } + + if(counterClockwise) { + largeArcFlag = diff > Math.PI ? 0 : 1; + } else { + largeArcFlag = diff > Math.PI ? 1 : 0; + } + + this.lineTo(startX, startY); + this.__addPathCommand(format("A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}", + {rx:radiusX, ry:radiusY, xAxisRotation:rotation*(180/Math.PI), largeArcFlag:largeArcFlag, sweepFlag:sweepFlag, endX:endX, endY:endY})); + + this.__currentPosition = {x: endX, y: endY}; + }; + /** * Generates a ClipPath from the clip command. */ diff --git a/test/index.js b/test/index.js index e5cfbdd..8bdf8ee 100644 --- a/test/index.js +++ b/test/index.js @@ -3,6 +3,7 @@ import arc from './tests/arc' import arcTo from './tests/arcTo' import arcTo2 from './tests/arcTo2' import emptyArc from './tests/emptyArc' +import ellipse from './tests/ellipse' import fillstyle from './tests/fillstyle' import globalAlpha from './tests/globalalpha' import gradient from './tests/gradient' @@ -23,6 +24,7 @@ const tests = [ arcTo, arcTo2, emptyArc, + ellipse, fillstyle, globalAlpha, gradient, diff --git a/test/rendering.test.js b/test/rendering.test.js index b52cdec..a2fe1da 100644 --- a/test/rendering.test.js +++ b/test/rendering.test.js @@ -4,6 +4,7 @@ import arc from './tests/arc' import arcTo from './tests/arcTo' import arcTo2 from './tests/arcTo2' import emptyArc from './tests/emptyArc' +import ellipse from './tests/ellipse' import fillstyle from './tests/fillstyle' import globalAlpha from './tests/globalalpha' import gradient from './tests/gradient' @@ -24,6 +25,7 @@ const tests = { arcTo, arcTo2, emptyArc, + ellipse, fillstyle, globalAlpha, gradient, diff --git a/test/tests/ellipse.js b/test/tests/ellipse.js new file mode 100644 index 0000000..b657398 --- /dev/null +++ b/test/tests/ellipse.js @@ -0,0 +1,28 @@ +export default function ellipse(ctx) { + + //ctx.scale(2,0.5) + + // Draw shapes + for (let i = 0; i < 4; i++) { + for (let j = 0; j < 4; j++) { + ctx.beginPath(); + var x = 25 + j * 50; // x coordinate + var y = 25 + i * 50; // y coordinate + var radiusX = 20; // Arc radius + var radiusY = 10; // Arc radius + var rotation = Math.PI + (Math.PI * (i+j)) / 8; + var startAngle = 0; // Starting point on circle + var endAngle = Math.PI + (Math.PI * j) / 2; // End point on circle + var clockwise = i % 2 == 0 ? false : true; // clockwise or anticlockwise + + ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, clockwise); + + if (i > 1) { + ctx.fill(); + } else { + ctx.stroke(); + } + } + } + +}; \ No newline at end of file From 6c209fccdfdfba0a1ca57ce4168322aabe26e63f Mon Sep 17 00:00:00 2001 From: k1w1 Date: Fri, 15 Jul 2022 17:47:47 -0700 Subject: [PATCH 2/2] Add support for ellipses --- context.js | 30 +++++++++++++++++++++++------- test/tests/ellipse.js | 43 ++++++++++++++++++++----------------------- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/context.js b/context.js index 875d2e9..d0de57b 100644 --- a/context.js +++ b/context.js @@ -1037,19 +1037,27 @@ export default (function () { if (startAngle === endAngle) { 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; + startAngle = startAngle % (2*Math.PI); endAngle = endAngle % (2*Math.PI); if(startAngle === endAngle) { endAngle = ((endAngle + (2*Math.PI)) - 0.001 * (counterClockwise ? -1 : 1)) % (2*Math.PI); } var endX = x + Math.cos(-rotation) * radiusX * Math.cos(endAngle) - + Math.sin(-rotation) * radiusY * Math.sin(endAngle), + + Math.sin(-rotation) * radiusY * Math.sin(endAngle), endY = y - Math.sin(-rotation) * radiusX * Math.cos(endAngle) - + Math.cos(-rotation) * radiusY * Math.sin(endAngle), + + Math.cos(-rotation) * radiusY * Math.sin(endAngle), startX = x + Math.cos(-rotation) * radiusX * Math.cos(startAngle) - + Math.sin(-rotation) * radiusY * Math.sin(startAngle), + + Math.sin(-rotation) * radiusY * Math.sin(startAngle), startY = y - Math.sin(-rotation) * radiusX * Math.cos(startAngle) - + Math.cos(-rotation) * radiusY * Math.sin(startAngle), + + Math.cos(-rotation) * radiusY * Math.sin(startAngle), sweepFlag = counterClockwise ? 0 : 1, largeArcFlag = 0, diff = endAngle - startAngle; @@ -1063,10 +1071,18 @@ export default (function () { } else { largeArcFlag = diff > Math.PI ? 1 : 0; } - - this.lineTo(startX, startY); + + this.lineTo(startX / scaleX, startY / scaleY); this.__addPathCommand(format("A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}", - {rx:radiusX, ry:radiusY, xAxisRotation:rotation*(180/Math.PI), largeArcFlag:largeArcFlag, sweepFlag:sweepFlag, endX:endX, endY:endY})); + { + rx:radiusX, + ry:radiusY, + xAxisRotation:rotation*(180/Math.PI), + largeArcFlag:largeArcFlag, + sweepFlag:sweepFlag, + endX:endX, + endY:endY + })); this.__currentPosition = {x: endX, y: endY}; }; diff --git a/test/tests/ellipse.js b/test/tests/ellipse.js index b657398..d2f90dc 100644 --- a/test/tests/ellipse.js +++ b/test/tests/ellipse.js @@ -1,28 +1,25 @@ export default function ellipse(ctx) { + // Draw shapes + for (let i = 0; i < 4; i++) { + for (let j = 0; j < 3; j++) { + ctx.beginPath(); + var x = 25 + j * 50; // x coordinate + var y = 25 + i * 50; // y coordinate + var radiusX = 20; // Arc radius + var radiusY = 10; // Arc radius + var rotation = Math.PI + (Math.PI * (i+j)) / 8; + var startAngle = 0; // Starting point on circle + var endAngle = Math.PI + (Math.PI * j) / 2; // End point on circle + var clockwise = i % 2 == 0 ? false : true; // clockwise or anticlockwise - //ctx.scale(2,0.5) + ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, clockwise); - // Draw shapes - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 4; j++) { - ctx.beginPath(); - var x = 25 + j * 50; // x coordinate - var y = 25 + i * 50; // y coordinate - var radiusX = 20; // Arc radius - var radiusY = 10; // Arc radius - var rotation = Math.PI + (Math.PI * (i+j)) / 8; - var startAngle = 0; // Starting point on circle - var endAngle = Math.PI + (Math.PI * j) / 2; // End point on circle - var clockwise = i % 2 == 0 ? false : true; // clockwise or anticlockwise - - ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, clockwise); - - if (i > 1) { - ctx.fill(); - } else { - ctx.stroke(); - } - } - } + if (i > 1) { + ctx.fill(); + } else { + ctx.stroke(); + } + } + } }; \ No newline at end of file