From a26f4d887d30188bec9506a0b918879f055fe11e Mon Sep 17 00:00:00 2001 From: asl97 Date: Sun, 10 May 2026 17:42:10 +0800 Subject: [PATCH 1/2] PoC demo of centering on anchor Note: limitation of only being able to render a shape to one SVG Illustration at any one time --- demos/centered/center.js | 163 ++++++++++++++++++++++++++++++++++++++ demos/centered/index.html | 60 ++++++++++++++ js/illustration.js | 31 +++++--- 3 files changed, 245 insertions(+), 9 deletions(-) create mode 100644 demos/centered/center.js create mode 100644 demos/centered/index.html diff --git a/demos/centered/center.js b/demos/centered/center.js new file mode 100644 index 0000000..7d7adc5 --- /dev/null +++ b/demos/centered/center.js @@ -0,0 +1,163 @@ +// ----- setup ----- // +var isSpinning = true; + +var model = new Zdog.Anchor(); + +// Made with Zdog + +const orange = '#E62'; +const garnet = '#C25'; +const eggplant = '#636'; + +// origin dot +var dot = new Zdog.Shape({ + addTo: model, + stroke: 8, + color: eggplant, +}); + +var zCircle = new Zdog.Ellipse({ + addTo: model, + diameter: 20, + quarters: 2, + closed: true, + translate: { z: 40 }, + scale: 1, + stroke: 8, + fill: true, + color: eggplant, +}); + +// z line +new Zdog.Shape({ + addTo: zCircle, + path: [ {}, zCircle.translate.copy().multiply({ z: -1 }) ], + scale: 1/zCircle.scale.z, + stroke: 2, + color: zCircle.color, +}); + +var xRect = new Zdog.Rect({ + addTo: zCircle, + width: 20, + height: 20, + translate: { x: 40 }, + stroke: 8, + fill: true, + color: garnet, +}); + +// x line +new Zdog.Shape({ + addTo: xRect, + path: [ {}, xRect.translate.copy().multiply({ x: -1 }) ], + stroke: 2, + color: xRect.color, +}); + +var yTri = new Zdog.Polygon({ + addTo: xRect, + radius: 10, + sides: 3, + translate: { y: -60 }, + stroke: 8, + fill: true, + color: orange, +}); + +// y line +new Zdog.Shape({ + addTo: yTri, + path: [ {}, yTri.translate.copy().multiply({ y: -1 }) ], + stroke: 2, + color: yTri.color, +}); + +var canvasDot = new Zdog.Illustration({ + element: 'canvas.dot', + dragRotate: model, + //centered: dot, + onDragStart: function() { + isSpinning = false; + }, +}); + +var canvasEggplant = new Zdog.Illustration({ + element: 'canvas.eggplant', + dragRotate: model, + centered: zCircle, + onDragStart: function() { + isSpinning = false; + }, +}); +var canvasGarnet = new Zdog.Illustration({ + element: 'canvas.garnet', + dragRotate: model, + centered: xRect, + onDragStart: function() { + isSpinning = false; + }, +}); +var canvasOrange = new Zdog.Illustration({ + element: 'canvas.orange', + dragRotate: model, + centered: yTri, + onDragStart: function() { + isSpinning = false; + }, +}); + +var svgDot = new Zdog.Illustration({ + element: 'svg.dot', + dragRotate: model, + //centered: dot, + onDragStart: function() { + isSpinning = false; + }, +}); +var svgEggplant = new Zdog.Illustration({ + element: 'svg.eggplant', + dragRotate: model, + centered: zCircle, + onDragStart: function() { + isSpinning = false; + }, +}); +var svgGarnet = new Zdog.Illustration({ + element: 'svg.garnet', + dragRotate: model, + centered: xRect, + onDragStart: function() { + isSpinning = false; + }, +}); +var svgOrange = new Zdog.Illustration({ + element: 'svg.orange', + dragRotate: model, + centered: yTri, + onDragStart: function() { + isSpinning = false; + }, +}); + +// ----- animate ----- // + +function animate() { + model.rotate.y += isSpinning ? 0.03 : 0; + model.updateGraph(); + + canvasDot.renderGraph( model ); + canvasEggplant.renderGraph( model ); + canvasGarnet.renderGraph( model ); + canvasOrange.renderGraph( model ); + + svgDot.renderGraph( model ); + svgEggplant.renderGraph( model ); + svgGarnet.renderGraph( model ); + svgOrange.renderGraph( model ); + + requestAnimationFrame( animate ); +} + +animate(); + diff --git a/demos/centered/index.html b/demos/centered/index.html new file mode 100644 index 0000000..66bee4d --- /dev/null +++ b/demos/centered/index.html @@ -0,0 +1,60 @@ + + + + + + + centered + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/illustration.js b/js/illustration.js index 46a961e..efa01ff 100644 --- a/js/illustration.js +++ b/js/illustration.js @@ -157,9 +157,13 @@ Illustration.prototype.prerenderCanvas = function() { ctx.clearRect( 0, 0, this.canvasWidth, this.canvasHeight ); ctx.save(); if ( this.centered ) { - var centerX = this.width / 2 * this.pixelRatio; - var centerY = this.height / 2 * this.pixelRatio; - ctx.translate( centerX, centerY ); + var centerX = this.width / 2; + var centerY = this.height / 2; + if (this.centered.origin) { + centerX -= this.centered.renderOrigin.x; + centerY -= this.centered.renderOrigin.y; + } + ctx.translate( centerX * this.pixelRatio, centerY * this.pixelRatio); } var scale = this.pixelRatio * this.zoom; ctx.scale( scale, scale ); @@ -172,6 +176,19 @@ Illustration.prototype.postrenderCanvas = function() { // ----- svg ----- // +Illustration.prototype.prerenderSvg = function() { + var viewWidth = this.width / this.zoom; + var viewHeight = this.height / this.zoom; + var viewX = this.centered ? -viewWidth/2 : 0; + var viewY = this.centered ? -viewHeight/2 : 0; + if (this.centered.origin) { + viewX += this.centered.renderOrigin.x; + viewY += this.centered.renderOrigin.y; + } + this.element.setAttribute( 'viewBox', viewX + ' ' + viewY + ' ' + + viewWidth + ' ' + viewHeight ); +} + Illustration.prototype.setSvg = function( element ) { this.element = element; this.isSvg = true; @@ -185,12 +202,7 @@ Illustration.prototype.setSvg = function( element ) { Illustration.prototype.setSizeSvg = function( width, height ) { this.width = width; this.height = height; - var viewWidth = width / this.zoom; - var viewHeight = height / this.zoom; - var viewX = this.centered ? -viewWidth/2 : 0; - var viewY = this.centered ? -viewHeight/2 : 0; - this.element.setAttribute( 'viewBox', viewX + ' ' + viewY + ' ' + - viewWidth + ' ' + viewHeight ); + this.prerenderSvg(); if ( this.resize ) { // remove size attributes, let size be determined by viewbox this.element.removeAttribute('width'); @@ -204,6 +216,7 @@ Illustration.prototype.setSizeSvg = function( width, height ) { Illustration.prototype.renderGraphSvg = function( item ) { item = item || this; empty( this.element ); + this.prerenderSvg(); this.onPrerender( this.element ); Anchor.prototype.renderGraphSvg.call( item, this.element ); }; From e930c944f04c48afef8bc8094cd48c3a230cfdc7 Mon Sep 17 00:00:00 2001 From: asl97 Date: Sun, 10 May 2026 20:02:34 +0800 Subject: [PATCH 2/2] Add "isolated" mode to Illustration for working around limitation of zdog only being able to render a shape to one SVG instance at any one time --- demos/centered/center.js | 3 +++ js/illustration.js | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/demos/centered/center.js b/demos/centered/center.js index 7d7adc5..dfaacfd 100644 --- a/demos/centered/center.js +++ b/demos/centered/center.js @@ -110,6 +110,7 @@ var canvasOrange = new Zdog.Illustration({ var svgDot = new Zdog.Illustration({ element: 'svg.dot', dragRotate: model, + isolated: true, //centered: dot, onDragStart: function() { isSpinning = false; @@ -118,6 +119,7 @@ var svgDot = new Zdog.Illustration({ var svgEggplant = new Zdog.Illustration({ element: 'svg.eggplant', dragRotate: model, + isolated: true, centered: zCircle, onDragStart: function() { isSpinning = false; @@ -126,6 +128,7 @@ var svgEggplant = new Zdog.Illustration({ var svgGarnet = new Zdog.Illustration({ element: 'svg.garnet', dragRotate: model, + isolated: true, centered: xRect, onDragStart: function() { isSpinning = false; diff --git a/js/illustration.js b/js/illustration.js index efa01ff..21c3826 100644 --- a/js/illustration.js +++ b/js/illustration.js @@ -21,6 +21,7 @@ var TAU = utils.TAU; var Illustration = Anchor.subclass({ element: undefined, centered: true, + isolated: false, zoom: 1, dragRotate: false, resize: false, @@ -189,6 +190,12 @@ Illustration.prototype.prerenderSvg = function() { viewWidth + ' ' + viewHeight ); } +Illustration.prototype.postrenderSvg = function() { + if (this.isolated){ + this.element.innerHTML = this.element.innerHTML; + } +} + Illustration.prototype.setSvg = function( element ) { this.element = element; this.isSvg = true; @@ -219,6 +226,7 @@ Illustration.prototype.renderGraphSvg = function( item ) { this.prerenderSvg(); this.onPrerender( this.element ); Anchor.prototype.renderGraphSvg.call( item, this.element ); + this.postrenderSvg(); }; function empty( element ) {