diff --git a/packages/core/src/part.mjs b/packages/core/src/part.mjs index 8e9517ba3fd..0ef1e047272 100644 --- a/packages/core/src/part.mjs +++ b/packages/core/src/part.mjs @@ -111,31 +111,15 @@ Part.prototype.boundary = function () { if (topLeft.y === Infinity) topLeft.y = 0 if (bottomRight.x === -Infinity) bottomRight.x = 0 if (bottomRight.y === -Infinity) bottomRight.y = 0 - // Add margin - let margin = this.context.settings.margin - if (this.context.settings.paperless && margin < 10) margin = 10 - this.topLeft = new Point(topLeft.x - margin, topLeft.y - margin) - this.bottomRight = new Point(bottomRight.x + margin, bottomRight.y + margin) + + this.topLeft = topLeft + this.bottomRight = bottomRight this.width = this.bottomRight.x - this.topLeft.x this.height = this.bottomRight.y - this.topLeft.y return this } -/** Homes part so that its top left corner is in (0,0) */ -Part.prototype.home = function () { - if (this.topLeft !== false) return this - else this.boundary() - if (this.topLeft.x == 0 && this.topLeft.y == 0) return this - else { - this.attr('transform', `translate(${this.topLeft.x * -1}, ${this.topLeft.y * -1})`) - this.layout.move.x = this.topLeft.x * -1 - this.layout.move.y = this.topLeft.y * -1 - } - - return this -} - /** Adds an attribute. This is here to make this call chainable in assignment */ Part.prototype.attr = function (name, value, overwrite = false) { if (overwrite) this.attributes.set(name, value) diff --git a/packages/core/src/pattern.mjs b/packages/core/src/pattern.mjs index 5e5b1388252..bb7aacfc44b 100644 --- a/packages/core/src/pattern.mjs +++ b/packages/core/src/pattern.mjs @@ -104,6 +104,19 @@ Pattern.prototype.__createPartWithContext = function (name) { return part } +Pattern.prototype.__createStackWithContext = function (name) { + // Context object to add to Stack closure + const stack = new Stack() + stack.name = name + stack.context = { + config: this.config, + settings: this.settings, + store: this.store, + } + + return stack +} + // Merges default for options with user-provided options Pattern.prototype.__loadOptionDefaults = function () { if (Object.keys(this.config.options).length < 1) return this @@ -548,7 +561,8 @@ Pattern.prototype.pack = function () { // First, create all stacks this.stacks = {} for (const [name, part] of Object.entries(this.parts)) { - if (typeof this.stacks[part.stack] === 'undefined') this.stacks[part.stack] = new Stack(part.stack) + if (typeof this.stacks[part.stack] === 'undefined') + this.stacks[part.stack] = this.__createStackWithContext(part.stack) this.stacks[part.stack].addPart(part) } @@ -558,7 +572,8 @@ Pattern.prototype.pack = function () { stack.attributes.remove('transform') if (!this.isStackHidden(key)) { stack.home() - if (this.settings.layout === true) bins.push({ id: key, width: stack.width, height: stack.height }) + if (this.settings.layout === true) + bins.push({ id: key, width: stack.width, height: stack.height }) else { if (this.width < stack.width) this.width = stack.width if (this.height < stack.height) this.height = stack.height @@ -573,7 +588,6 @@ Pattern.prototype.pack = function () { if (bin.x !== 0 || bin.y !== 0) { stack.attr('transform', `translate(${bin.x}, ${bin.y})`) } - this.autoLayout.stacks[bin.id].move = { x: bin.x + stack.layout.move.x, y: bin.y + stack.layout.move.y, @@ -845,6 +859,12 @@ Pattern.prototype.getRenderProps = function () { } } } + props.stacks = {} + for (let s in this.stacks) { + if (!this.isStackHidden(s)) { + props.stacks[s] = this.stacks[s] + } + } return props } diff --git a/packages/core/src/stack.mjs b/packages/core/src/stack.mjs index 76aa73b382c..7f516a5be6b 100644 --- a/packages/core/src/stack.mjs +++ b/packages/core/src/stack.mjs @@ -2,7 +2,7 @@ import { Attributes } from './attributes.mjs' import { Point } from './point.mjs' import * as utils from './utils.mjs' -export function Stack(name=null) { +export function Stack(name = null) { // Non-enumerable properties utils.addNonEnumProp(this, 'freeId', 0) utils.addNonEnumProp(this, 'topLeft', false) @@ -20,20 +20,20 @@ export function Stack(name=null) { } /* Adds a part to the stack */ -Stack.prototype.addPart = function(part) { +Stack.prototype.addPart = function (part) { if (part) this.parts.add(part) return this } /* Returns a list of parts in this stack */ -Stack.prototype.getPartList = function(part) { +Stack.prototype.getPartList = function (part) { return [...this.parts] } /* Returns a list of names of parts in this stack */ -Stack.prototype.getPartNames = function(part) { - return [...this.parts].map(p => p.name) +Stack.prototype.getPartNames = function (part) { + return [...this.parts].map((p) => p.name) } /** Homes the stack so that its top left corner is in (0,0) */ @@ -58,9 +58,11 @@ Stack.prototype.home = function () { /** Calculates the stack's bounding box and sets it */ Stack.prototype.home = function () { + if (this.topLeft) return this // Cached this.topLeft = new Point(Infinity, Infinity) this.bottomRight = new Point(-Infinity, -Infinity) for (const part of this.getPartList()) { + part.boundary() if (part.topLeft.x < this.topLeft.x) this.topLeft.x = part.topLeft.x if (part.topLeft.y < this.topLeft.y) this.topLeft.y = part.topLeft.y if (part.bottomRight.x > this.bottomRight.x) this.bottomRight.x = part.bottomRight.x @@ -73,8 +75,53 @@ Stack.prototype.home = function () { if (this.bottomRight.x === -Infinity) this.bottomRight.x = 0 if (this.bottomRight.y === -Infinity) this.bottomRight.y = 0 + // Add margin + let margin = this.context.settings.margin + if (this.context.settings.paperless && margin < 10) margin = 10 + this.topLeft.x -= margin + this.topLeft.y -= margin + this.bottomRight.x += margin + this.bottomRight.y += margin + + // Set dimensions this.width = this.bottomRight.x - this.topLeft.x this.height = this.bottomRight.y - this.topLeft.y + this.width = this.bottomRight.x - this.topLeft.x + this.height = this.bottomRight.y - this.topLeft.y + + // Add transform + this.anchor = this.getAnchor() + + if (this.topLeft.x === this.anchor.x && this.topLeft.y === this.anchor.y) return this + else { + this.attr('transform', `translate(${this.anchor.x - this.topLeft.x}, ${this.anchor.y - this.topLeft.y})`) + this.layout.move.x = this.anchor.x - this.topLeft.x + this.layout.move.y = this.anchor.y - this.topLeft.y + } + + return this +} + +/** Finds the anchor to aling parts in this stack */ +Stack.prototype.getAnchor = function() { + let anchorPoint = true + let gridAnchorPoint = true + const parts = this.getPartList() + for (const part of parts) { + if (typeof part.points.anchor === 'undefined') anchorPoint = false + if (typeof part.points.gridAnchor === 'undefined') gridAnchorPoint = false + } + + if (anchorPoint) return parts[0].points.anchor + if (gridAnchorPoint) return parts[0].points.gridAnchor + + return new Point(0,0) +} + +/** Adds an attribute. This is here to make this call chainable in assignment */ +Stack.prototype.attr = function (name, value, overwrite = false) { + if (overwrite) this.attributes.set(name, value) + else this.attributes.add(name, value) return this } diff --git a/packages/core/tests/stacks.test.mjs b/packages/core/tests/stacks.test.mjs index e22a18cb85a..1331325baf1 100644 --- a/packages/core/tests/stacks.test.mjs +++ b/packages/core/tests/stacks.test.mjs @@ -4,7 +4,6 @@ import { round, Design, Point, pctBasedOn } from '../src/index.mjs' const expect = chai.expect describe('Stacks', () => { - describe('Pattern.init()', () => { const partA = { name: 'test.partA', @@ -12,9 +11,9 @@ describe('Stacks', () => { options: { size: { pct: 40, min: 20, max: 80 }, }, - draft: ({ points, Point, paths, Path, part, store, measurements, options}) => { + draft: ({ points, Point, paths, Path, part, store, measurements, options }) => { store.set('size', measurements.head * options.size) - points.from = new Point(0,0) + points.from = new Point(0, 0) points.to = new Point(0, store.get('size')) paths.line = new Path().move(points.from).line(points.to) return part @@ -25,8 +24,8 @@ describe('Stacks', () => { name: 'test.partB', measurements: ['head'], after: partA, - draft: ({ points, Point, paths, Path, part, store}) => { - points.from = new Point(0,store.get('size')) + draft: ({ points, Point, paths, Path, part, store }) => { + points.from = new Point(0, store.get('size')) points.to = new Point(store.get('size'), store.get('size')) paths.line = new Path().move(points.from).line(points.to) return part @@ -36,7 +35,7 @@ describe('Stacks', () => { const partC = { name: 'test.partC', after: partB, - draft: ({ points, Point, paths, Path, part, store}) => { + draft: ({ points, Point, paths, Path, part, store }) => { points.from = new Point(store.get('size'), store.get('size')) points.to = new Point(store.get('size'), 0) paths.line = new Path().move(points.from).line(points.to) @@ -47,13 +46,13 @@ describe('Stacks', () => { const partD = { name: 'test.partD', after: partC, - draft: ({ points, Point, paths, Path, part, store}) => { + draft: ({ points, Point, paths, Path, part, store }) => { points.from = new Point(store.get('size'), 0) points.to = new Point(0, 0) paths.line = new Path().move(points.from).line(points.to) return part }, - // stack: 'box', + // stack: 'box', } const Pattern = new Design({ @@ -65,8 +64,8 @@ describe('Stacks', () => { }) const pattern = new Pattern({ measurements: { - head: 400 - } + head: 400, + }, }) pattern.draft() console.log(pattern.store.logs) @@ -90,6 +89,5 @@ describe('Stacks', () => { pattern.config.resolvedDependencies['test.partC'].indexOf('test.partB') !== -1 ).to.equal(true) }) - }) }) diff --git a/sites/shared/components/workbench/draft/index.js b/sites/shared/components/workbench/draft/index.js index 4e6a3959d2d..b0625c095e8 100644 --- a/sites/shared/components/workbench/draft/index.js +++ b/sites/shared/components/workbench/draft/index.js @@ -27,7 +27,7 @@ const LabDraft = props => { return ( <> - {(!patternProps || patternProps.events?.error?.length > 0) + {(!patternProps || patternProps.logs?.error?.length > 0) ? : null } diff --git a/sites/shared/components/workbench/draft/stack.js b/sites/shared/components/workbench/draft/stack.js new file mode 100644 index 00000000000..e733e205759 --- /dev/null +++ b/sites/shared/components/workbench/draft/stack.js @@ -0,0 +1,20 @@ +import Part from './part' +import { getProps } from './utils' + +const Stack = props => { + const { stackName, stack, patternProps, gist, app, updateGist, unsetGist, showInfo } = props + + return ( + + {[...stack.parts].map((part) => ( + + ))} + + ) +} + +export default Stack diff --git a/sites/shared/components/workbench/draft/svg-wrapper.js b/sites/shared/components/workbench/draft/svg-wrapper.js index 8f737841084..6aeaf14a799 100644 --- a/sites/shared/components/workbench/draft/svg-wrapper.js +++ b/sites/shared/components/workbench/draft/svg-wrapper.js @@ -2,7 +2,7 @@ import { SizeMe } from 'react-sizeme' import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch" import Svg from './svg' import Defs from './defs' -import Part from './part' +import Stack from './stack' /* What's with all the wrapping? * @@ -40,11 +40,11 @@ const SvgWrapper = props => { - {Object.keys(patternProps.parts).map((name) => ( - ( + ))}