1
0
Fork 0

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.
This commit is contained in:
joostdecock 2023-06-01 16:45:13 +02:00
parent fa437b9b16
commit a2800dddda
11 changed files with 119 additions and 51 deletions

View file

@ -54,6 +54,23 @@ Attributes.prototype.asPropsIfPrefixIs = function (prefix = '') {
return props 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 * Return a deep copy of this
* *

View file

@ -50,16 +50,23 @@ export function Part() {
* *
* @return {object} part - A plain object representing the 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 { return {
paths: this.paths, paths,
points: this.points, points,
snippets: this.snippets, snippets,
attributes: this.attributes, attributes: this.attributes.asRenderProps(),
height: this.height, height: this.height,
width: this.width, width: this.width,
bottomRight: this.bottomRight, bottomRight: this.bottomRight.asRenderProps(),
topLeft: this.topLeft, topLeft: this.topLeft.asRenderProps(),
} }
} }

View file

@ -111,6 +111,25 @@ Path.prototype.asPathstring = function () {
return d 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 * Chainable way to add an attribute
* *

View file

@ -164,6 +164,17 @@ Pattern.prototype.getRenderProps = function () {
return new PatternRenderer(this).getRenderProps() 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 // // Sampling //
////////////// //////////////

View file

@ -33,46 +33,23 @@ PatternRenderer.prototype.getRenderProps = function () {
this.__startRender() this.__startRender()
this.svg.__runHooks('preRender') this.svg.__runHooks('preRender')
let props = { const props = {
svg: this.svg, svg: this.svg.asRenderProps(),
width: this.pattern.width, width: this.pattern.width,
height: this.pattern.height, height: this.pattern.height,
autoLayout: this.pattern.autoLayout, autoLayout: this.pattern.autoLayout,
settings: this.pattern.settings, settings: this.pattern.settings,
parts: [],
stacks: {}, 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) { for (let s in this.pattern.stacks) {
if (!this.pattern.__isStackHidden(s)) { 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.`) } 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') this.svg.__runHooks('postRender')
return props return props
} }

View file

@ -346,6 +346,19 @@ Point.prototype.translate = function (x, y) {
return p 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 // // PRIVATE METHODS //
////////////////////////////////////////////// //////////////////////////////////////////////

View file

@ -52,6 +52,19 @@ Snippet.prototype.clone = function () {
return clone 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 // // PRIVATE METHODS //
////////////////////////////////////////////// //////////////////////////////////////////////

View file

@ -27,10 +27,15 @@ Stack.prototype.addPart = function (part) {
} }
/* Returns a stack object suitbale for renderprops */ /* Returns a stack object suitbale for renderprops */
Stack.prototype.asProps = function () { Stack.prototype.asRenderProps = function () {
return { return {
...this, name: this.name,
parts: [...this.parts], attributes: this.attributes.asRenderProps(),
topLeft: this.topLeft,
bottomRight: this.bottomRight,
width: this.width,
height: this.height,
parts: [...this.parts].map((part) => part.asRenderProps()),
} }
} }

View file

@ -39,6 +39,21 @@ export function Svg(pattern) {
// PUBLIC METHODS // // 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 * Renders a drafted Pattern as SVG
* *

View file

@ -173,7 +173,7 @@ describe('Pattern', () => {
layout: { stacks: { test: { flipX: true } }, width: 300, height: 400 }, layout: { stacks: { test: { flipX: true } }, width: 300, height: 400 },
}) })
const props = pattern.draft().getRenderProps() 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.width).to.equal(300)
expect(props.height).to.equal(400) expect(props.height).to.equal(400)
}) })

View file

@ -15,24 +15,15 @@ describe('Pattern Rendering', () => {
} }
const design = new Design({ parts: [part] }) const design = new Design({ parts: [part] })
const pattern = new design({}) const pattern = new design({}).draft()
const props = pattern.draft().getRenderProps() 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', () => { it('Should not include hidden stacks', () => {
expect(props.stacks).not.to.have.property('test') expect(props.stacks).not.to.have.property('test')
}) })
it('Should log that it has skipped a hidden stack', () => { it('Should log that it has skipped a hidden stack', () => {
expect(props.logs.pattern.info).to.include( expect(logs.pattern.info).to.include('Stack test is hidden. Skipping in render props.')
'Stack test is hidden. Skipping in render props.'
)
}) })
}) })
}) })