From a2800ddddaef4c20b2e24de5685cfb55624241af Mon Sep 17 00:00:00 2001 From: joostdecock Date: Thu, 1 Jun 2023 16:45:13 +0200 Subject: [PATCH] feat(core): Added Pattern.getLogs() and updated Pattern.getRenderProps() The data returned by `Pattern.getRenderProps()` was not serializable as we were returning `this` all over the place, thereby including marcors, log methods, cyclic object references, and so on. This commit changes that by implementing a `.asRenderProp()` method on all of the various objects (stack, part, path, point, snippet, attributes, svg) and only including data that can be serialized. In addition, we no longer include the logs in the renderProps because they are not related to rendering the pattern. Instead, the new method `Pattern.getLogs()` gives you the logs. --- packages/core/src/attributes.mjs | 17 ++++++++++ packages/core/src/part.mjs | 21 ++++++++----- packages/core/src/path.mjs | 19 ++++++++++++ packages/core/src/pattern/index.mjs | 11 +++++++ .../core/src/pattern/pattern-renderer.mjs | 31 +++---------------- packages/core/src/point.mjs | 13 ++++++++ packages/core/src/snippet.mjs | 13 ++++++++ packages/core/src/stack.mjs | 11 +++++-- packages/core/src/svg.mjs | 15 +++++++++ packages/core/tests/pattern-other.test.mjs | 2 +- packages/core/tests/pattern-renderer.test.mjs | 17 +++------- 11 files changed, 119 insertions(+), 51 deletions(-) diff --git a/packages/core/src/attributes.mjs b/packages/core/src/attributes.mjs index 211c7b28fe6..1d17264a606 100644 --- a/packages/core/src/attributes.mjs +++ b/packages/core/src/attributes.mjs @@ -54,6 +54,23 @@ Attributes.prototype.asPropsIfPrefixIs = function (prefix = '') { return props } +/** + * Returns attributes as an object suitable for inclusion in renderprops + * + * @return {object} attributes - A plain object representing the attributes + */ +Attributes.prototype.asRenderProps = function () { + return { + list: this.list, + forSvg: this.render(), + forCss: this.renderAsCss(), + circle: this.getAsArray('data-circle'), + circleProps: this.asPropsIfPrefixIs('data-circle-'), + text: this.getAsArray('data-text'), + textProps: this.asPropsIfPrefixIs('data-text-'), + } +} + /** * Return a deep copy of this * diff --git a/packages/core/src/part.mjs b/packages/core/src/part.mjs index ff6b1ef56d3..581f4bfffd0 100644 --- a/packages/core/src/part.mjs +++ b/packages/core/src/part.mjs @@ -50,16 +50,23 @@ export function Part() { * * @return {object} part - A plain object representing the part */ -Part.prototype.asProps = function () { +Part.prototype.asRenderProps = function () { + const paths = {} + for (const i in this.paths) paths[i] = this.paths[i].asRenderProps() + const points = {} + for (const i in this.points) points[i] = this.points[i].asRenderProps() + const snippets = {} + for (const i in this.snippets) snippets[i] = this.snippets[i].asRenderProps() + return { - paths: this.paths, - points: this.points, - snippets: this.snippets, - attributes: this.attributes, + paths, + points, + snippets, + attributes: this.attributes.asRenderProps(), height: this.height, width: this.width, - bottomRight: this.bottomRight, - topLeft: this.topLeft, + bottomRight: this.bottomRight.asRenderProps(), + topLeft: this.topLeft.asRenderProps(), } } diff --git a/packages/core/src/path.mjs b/packages/core/src/path.mjs index bdaa2c05774..937e06ae3c3 100644 --- a/packages/core/src/path.mjs +++ b/packages/core/src/path.mjs @@ -111,6 +111,25 @@ Path.prototype.asPathstring = function () { return d } +/** + * Returns a path as an object suitable for inclusion in renderprops + * + * @return {object} path - A plain object representing the path + */ +Path.prototype.asRenderProps = function () { + return { + attributes: this.attributes.asRenderProps(), + hidden: this.hidden, + name: this.name, + ops: this.ops, + topLeft: this.topLeft, + bottomRight: this.bottomRight, + width: this.bottomRight.x - this.topLeft.x, + height: this.bottomRight.y - this.topLeft.y, + d: this.asPathstring(), + } +} + /** * Chainable way to add an attribute * diff --git a/packages/core/src/pattern/index.mjs b/packages/core/src/pattern/index.mjs index 71521b1b4c8..0959e55272d 100644 --- a/packages/core/src/pattern/index.mjs +++ b/packages/core/src/pattern/index.mjs @@ -164,6 +164,17 @@ Pattern.prototype.getRenderProps = function () { return new PatternRenderer(this).getRenderProps() } +/** Returns the pattern logs + * + * @return {object} logs - The Pattern logs + */ +Pattern.prototype.getLogs = function () { + return { + pattern: this.store.logs, + sets: this.setStores.map((store) => store.logs), + } +} + ////////////// // Sampling // ////////////// diff --git a/packages/core/src/pattern/pattern-renderer.mjs b/packages/core/src/pattern/pattern-renderer.mjs index 4e418b0f0f7..b2dfe9e8cde 100644 --- a/packages/core/src/pattern/pattern-renderer.mjs +++ b/packages/core/src/pattern/pattern-renderer.mjs @@ -33,46 +33,23 @@ PatternRenderer.prototype.getRenderProps = function () { this.__startRender() this.svg.__runHooks('preRender') - let props = { - svg: this.svg, + const props = { + svg: this.svg.asRenderProps(), width: this.pattern.width, height: this.pattern.height, autoLayout: this.pattern.autoLayout, settings: this.pattern.settings, - parts: [], stacks: {}, } - for (const partSet of this.pattern.parts) { - const setPartProps = {} - for (let partName in partSet) { - const part = partSet[partName] - if (!part.hidden) { - setPartProps[partName] = { - ...partSet[partName].asProps(), - store: this.pattern.setStores[part.set], - } - } else if (this.pattern.setStores[part.set]) { - this.pattern.setStores[part.set].log.info( - `Part ${partName} is hidden in set ${part.set}. Not adding to render props` - ) - } - } - props.parts.push(setPartProps) - } - for (let s in this.pattern.stacks) { if (!this.pattern.__isStackHidden(s)) { - props.stacks[s] = this.pattern.stacks[s].asProps() + props.stacks[s] = this.pattern.stacks[s].asRenderProps() } else this.pattern.store.log.info(`Stack ${s} is hidden. Skipping in render props.`) } - props.logs = { - pattern: this.pattern.store.logs, - sets: this.pattern.setStores.map((store) => store.logs), - } - this.svg.__runHooks('postRender') + return props } diff --git a/packages/core/src/point.mjs b/packages/core/src/point.mjs index d6e49f51aff..0d179ad4963 100644 --- a/packages/core/src/point.mjs +++ b/packages/core/src/point.mjs @@ -346,6 +346,19 @@ Point.prototype.translate = function (x, y) { return p } +/** + * Returns a point as an object suitable for inclusion in renderprops + * + * @return {object} point - A plain object representing the point + */ +Point.prototype.asRenderProps = function () { + return { + x: this.x, + y: this.y, + attributes: this.attributes.asRenderProps(), + } +} + ////////////////////////////////////////////// // PRIVATE METHODS // ////////////////////////////////////////////// diff --git a/packages/core/src/snippet.mjs b/packages/core/src/snippet.mjs index 8756f9b121d..88244a4d120 100644 --- a/packages/core/src/snippet.mjs +++ b/packages/core/src/snippet.mjs @@ -52,6 +52,19 @@ Snippet.prototype.clone = function () { return clone } +/** + * Returns a snippet as an object suitable for inclusion in renderprops + * + * @return {object} snippet - A plain object representing the snippet + */ +Snippet.prototype.asRenderProps = function () { + return { + def: this.def, + anchor: this.anchor.asRenderProps(), + attributes: this.attributes.asRenderProps(), + } +} + ////////////////////////////////////////////// // PRIVATE METHODS // ////////////////////////////////////////////// diff --git a/packages/core/src/stack.mjs b/packages/core/src/stack.mjs index 9238f4b7667..277d8453194 100644 --- a/packages/core/src/stack.mjs +++ b/packages/core/src/stack.mjs @@ -27,10 +27,15 @@ Stack.prototype.addPart = function (part) { } /* Returns a stack object suitbale for renderprops */ -Stack.prototype.asProps = function () { +Stack.prototype.asRenderProps = function () { return { - ...this, - parts: [...this.parts], + name: this.name, + attributes: this.attributes.asRenderProps(), + topLeft: this.topLeft, + bottomRight: this.bottomRight, + width: this.width, + height: this.height, + parts: [...this.parts].map((part) => part.asRenderProps()), } } diff --git a/packages/core/src/svg.mjs b/packages/core/src/svg.mjs index 0dd58f963ea..712bcfb07e4 100644 --- a/packages/core/src/svg.mjs +++ b/packages/core/src/svg.mjs @@ -39,6 +39,21 @@ export function Svg(pattern) { // PUBLIC METHODS // ////////////////////////////////////////////// +/** + * Returns a svg as an object suitable for inclusion in renderprops + * + * @return {object} svg - A plain object representing the svg + */ +Svg.prototype.asRenderProps = function () { + return { + attributes: this.attributes.asRenderProps(), + layout: this.layout, + body: this.body, + style: this.style, + defs: this.defs, + } +} + /** * Renders a drafted Pattern as SVG * diff --git a/packages/core/tests/pattern-other.test.mjs b/packages/core/tests/pattern-other.test.mjs index 46fd350cdda..514f712f893 100644 --- a/packages/core/tests/pattern-other.test.mjs +++ b/packages/core/tests/pattern-other.test.mjs @@ -173,7 +173,7 @@ describe('Pattern', () => { layout: { stacks: { test: { flipX: true } }, width: 300, height: 400 }, }) const props = pattern.draft().getRenderProps() - expect(props.stacks.test.attributes.get('transform')).to.equal('scale(-1, 1)') + expect(props.stacks.test.attributes.list.transform[0]).to.equal('scale(-1, 1)') expect(props.width).to.equal(300) expect(props.height).to.equal(400) }) diff --git a/packages/core/tests/pattern-renderer.test.mjs b/packages/core/tests/pattern-renderer.test.mjs index 1888363d577..3d0eeb6716f 100644 --- a/packages/core/tests/pattern-renderer.test.mjs +++ b/packages/core/tests/pattern-renderer.test.mjs @@ -15,24 +15,15 @@ describe('Pattern Rendering', () => { } const design = new Design({ parts: [part] }) - const pattern = new design({}) - const props = pattern.draft().getRenderProps() + const pattern = new design({}).draft() + const props = pattern.getRenderProps() + const logs = pattern.getLogs() - it('Should not include hidden parts', () => { - expect(props.parts[0]).not.to.have.property('test') - }) - it('Should log that it has skipped a hidden part', () => { - expect(props.logs.sets[0].info).to.include( - 'Part test is hidden in set 0. Not adding to render props' - ) - }) it('Should not include hidden stacks', () => { expect(props.stacks).not.to.have.property('test') }) it('Should log that it has skipped a hidden stack', () => { - expect(props.logs.pattern.info).to.include( - 'Stack test is hidden. Skipping in render props.' - ) + expect(logs.pattern.info).to.include('Stack test is hidden. Skipping in render props.') }) }) })