diff --git a/plugins/plugin-annotations/src/pleat.mjs b/plugins/plugin-annotations/src/pleat.mjs index 3bc0f59c9ac..3d20d8a2a8e 100644 --- a/plugins/plugin-annotations/src/pleat.mjs +++ b/plugins/plugin-annotations/src/pleat.mjs @@ -1,68 +1,116 @@ +import { getIds } from './utils.mjs' + +/* + * Defaults for the pleat macro + */ +const macroDefaults = { + classes: { + arrow: 'note', + from: 'note', + to: 'note dashed', + }, + id: 'pleat', + margin: 35, + reverse: false, +} + // Export defs export const pleatDefs = [ { - name: 'notch', + name: 'pleat', def: ` - - + + `, }, ] -// Export macros -export const pleatMacros = { - pleat: function (so, { points, paths, Path, complete, scale }) { - if (so === false) { - delete points.pleatFrom - delete points.pleatFromIn - delete points.pleatTo - delete points.pleatToIn - delete paths.pleatTo - delete paths.pleatFrom - delete paths.pleatArrow - return true - } - so = { - margin: 35, - prefix: 'pleat', - reverse: false, - ...so, - } - if (complete) { - points[so.prefix + 'From'] = so.from - points[so.prefix + 'To'] = so.to - points[so.prefix + 'FromIn'] = points[so.prefix + 'From'].shift( - so.from.shiftTowards(so.to, 0.1).angle(so.from) + 270, - so.margin * scale - ) - points[so.prefix + 'ToIn'] = points[so.prefix + 'To'].shift( - so.from.shiftTowards(so.to, 0.1).angle(so.to) + 90, - so.margin * scale - ) - paths[so.prefix + 'PleatFrom'] = new Path() - .move(points[so.prefix + 'From']) - .line(points[so.prefix + 'FromIn']) - .attr('class', 'note' + (so.reverse ? ' dashed' : '')) - paths[so.prefix + 'PleatTo'] = new Path() - .move(points[so.prefix + 'To']) - .line(points[so.prefix + 'ToIn']) - .attr('class', 'note' + (so.reverse ? '' : ' dashed')) - paths[so.prefix + 'PleatArrow'] = new Path() - .move( - points[so.prefix + (so.reverse ? 'To' : 'From')].shiftFractionTowards( - points[so.prefix + (so.reverse ? 'ToIn' : 'FromIn')], - 0.25 - ) - ) - .line( - points[so.prefix + (so.reverse ? 'From' : 'To')].shiftFractionTowards( - points[so.prefix + (so.reverse ? 'FromIn' : 'ToIn')], - 0.25 - ) - ) - .attr('class', 'note') - .attr('marker-end', 'url(#pleatTo)') - } - }, +/* + * The rmpleat macro + */ +const rmpleat = function (id = macroDefaults.id, { paths, store, part }) { + for (const pid of Object.values( + store.get(['parts', part.name, 'macros', 'pleat', 'ids', id, 'paths'], {}) + )) + delete paths[pid] } + +/* + * The pleat macro + */ +const pleat = function (config, { points, paths, Path, complete, scale, store, part }) { + /* + * Don't add a pleat when complete is false, unless force is true + */ + if (!complete && !config.force) return + + /* + * Merge macro defaults with user-provided config to create the macro config (mc) + */ + const mc = { + ...macroDefaults, + ...config, + classes: macroDefaults.classes, + } + if (config.classes) mc.classes = { ...mc.classes, ...config.classes } + + /* + * Make sure mc.from and mc.to are Point instances + */ + if (!mc.from || typeof mc.from.attr !== 'function') { + log.warn(`Pleat macro called without a valid from point. Using (0,0) for from.`) + mc.from = new Point(0, 0) + } + if (!mc.to || typeof mc.to.attr !== 'function') { + log.warn(`Pleat macro called without a valid to point. Using (666,666) for to.`) + mc.to = new Point(666, 666) + } + + /* + * Get the list of IDs + * Initialize the verticle cadence + */ + const ids = getIds(['from', 'to', 'arrow'], mc.id, 'pleat') + + const toIn = mc.to.shift(mc.from.shiftTowards(mc.to, 0.1).angle(mc.to) + 90, mc.margin * scale) + const fromIn = mc.from.shift( + mc.from.shiftTowards(mc.to, 0.1).angle(mc.from) + 270, + mc.margin * scale + ) + /* + * Pleat line from + */ + paths[ids.from] = new Path() + .move(mc.from) + .line(fromIn) + .attr('class', mc.reverse ? mc.classes.to : mc.classes.from) + + /* + * Pleat line to + */ + paths[ids.to] = new Path() + .move(mc.to) + .line(toIn) + .attr('class', mc.reverse ? mc.classes.from : mc.classes.to) + + /* + * Pleat line arrow + */ + paths[ids.arrow] = mc.reverse + ? new Path() + .move(mc.to.shiftFractionTowards(toIn, 0.25)) + .line(mc.from.shiftFractionTowards(toIn, 0.25)) + : new Path() + .move(mc.from.shiftFractionTowards(fromIn, 0.25)) + .line(mc.to.shiftFractionTowards(fromIn, 0.25)) + paths[ids.arrow].attr('class', mc.classes.arrow).attr('marker-end', 'url(#pleatTo)') + + /* + * Store all IDs in the store so we can remove this macro with rmpleat + */ + store.set(['parts', part.name, 'macros', 'pleat', 'ids', mc.id, 'paths'], ids) +} + +// Export macros +export const pleatMacros = { pleat, rmpleat }