chore(plugin-annotations): Migrate scalebox
This commit is contained in:
parent
d94930f720
commit
509e6a3b85
1 changed files with 375 additions and 258 deletions
|
@ -1,34 +1,25 @@
|
|||
// Export macros
|
||||
export const scaleboxMacros = {
|
||||
scalebox: function (so, { store, points, paths, scale, Point, Path }) {
|
||||
// Passing `false` will remove the scalebox
|
||||
if (so === false) {
|
||||
for (let id of [
|
||||
'__scaleboxMetricTopLeft',
|
||||
'__scaleboxMetricTopRight',
|
||||
'__scaleboxMetricBottomRight',
|
||||
'__scaleboxMetricBottomLeft',
|
||||
'__scaleboxImperialTopLeft',
|
||||
'__scaleboxImperialTopRight',
|
||||
'__scaleboxImperialBottomRight',
|
||||
'__scaleboxImperialBottomLeft',
|
||||
'__scaleboxLead',
|
||||
'__scaleboxTitle',
|
||||
'__scaleboxText',
|
||||
'__scaleboxLink',
|
||||
'__scaleboxMetric',
|
||||
'__scaleboxImperial',
|
||||
])
|
||||
delete points[id]
|
||||
for (let id of ['__scaleboxMetric', '__scaleboxImperial']) delete paths[id]
|
||||
return true
|
||||
import { getIds } from './utils.mjs'
|
||||
|
||||
/*
|
||||
* Defaults for the title macro
|
||||
*/
|
||||
const macroDefaults = {
|
||||
classes: {
|
||||
lead: 'text-xs bold',
|
||||
title: 'text bold',
|
||||
text: 'text-sm',
|
||||
link: 'text-sm fill-note',
|
||||
metric: 'text-xs center',
|
||||
imperial: 'text-xs center',
|
||||
},
|
||||
}
|
||||
|
||||
// Convert scale to a value between 0 and 9, inclusive.
|
||||
const scaleIndex = Math.round(10 * Math.max(0.1, Math.min(1, scale))) - 1
|
||||
|
||||
// Metric width and height in mm and display width and height for each scale index.
|
||||
const metricSizes = [
|
||||
/*
|
||||
* Various sizes for scaleboxes per units
|
||||
*/
|
||||
const sizes = {
|
||||
scalebox: {
|
||||
metric: [
|
||||
[10, 5, '1cm', '0.5cm'],
|
||||
[20, 10, '2cm', '1cm'],
|
||||
[30, 15, '3cm', '1.5cm'],
|
||||
|
@ -39,15 +30,8 @@ export const scaleboxMacros = {
|
|||
[80, 40, '8cm', '4cm'],
|
||||
[90, 45, '9cm', '4.5cm'],
|
||||
[100, 50, '10cm', '5cm'],
|
||||
]
|
||||
|
||||
const metricWidth = metricSizes[scaleIndex][0]
|
||||
const metricHeight = metricSizes[scaleIndex][1]
|
||||
const metricDisplayWidth = metricSizes[scaleIndex][2]
|
||||
const metricDisplayHeight = metricSizes[scaleIndex][3]
|
||||
|
||||
// Imperial width and height in mm and display width and heigth for each scale index.
|
||||
const imperialSizes = [
|
||||
],
|
||||
imperial: [
|
||||
[25.4 * 0.5, 25.4 * 0.25, '½″', '¼″'],
|
||||
[25.4 * 0.875, 25.4 * 0.5, '⅞″', '½″'],
|
||||
[25.4 * 1.25, 25.4 * 0.625, '1 ¼″', '⅝″'],
|
||||
|
@ -58,225 +42,358 @@ export const scaleboxMacros = {
|
|||
[25.4 * 3.25, 25.4 * 1.625, '3 ¼″', '1 ⅝″'],
|
||||
[25.4 * 3.625, 25.4 * 1.875, '3 ⅝″', '1 ⅞″'],
|
||||
[25.4 * 4, 25.4 * 2, '4″', '2″'],
|
||||
]
|
||||
|
||||
const imperialWidth = imperialSizes[scaleIndex][0]
|
||||
const imperialHeight = imperialSizes[scaleIndex][1]
|
||||
const imperialDisplayWidth = imperialSizes[scaleIndex][2]
|
||||
const imperialDisplayHeight = imperialSizes[scaleIndex][3]
|
||||
|
||||
// Box points
|
||||
points.__scaleboxMetricTopLeft = new Point(
|
||||
so.at.x - metricWidth / 2,
|
||||
so.at.y - metricHeight / 2
|
||||
)
|
||||
points.__scaleboxMetricTopRight = new Point(
|
||||
so.at.x + metricWidth / 2,
|
||||
so.at.y - metricHeight / 2
|
||||
)
|
||||
points.__scaleboxMetricBottomLeft = new Point(
|
||||
so.at.x - metricWidth / 2,
|
||||
so.at.y + metricHeight / 2
|
||||
)
|
||||
points.__scaleboxMetricBottomRight = new Point(
|
||||
so.at.x + metricWidth / 2,
|
||||
so.at.y + metricHeight / 2
|
||||
)
|
||||
points.__scaleboxImperialTopLeft = new Point(
|
||||
so.at.x - imperialWidth / 2,
|
||||
so.at.y - imperialHeight / 2
|
||||
)
|
||||
points.__scaleboxImperialTopRight = new Point(
|
||||
so.at.x + imperialWidth / 2,
|
||||
so.at.y - imperialHeight / 2
|
||||
)
|
||||
points.__scaleboxImperialBottomLeft = new Point(
|
||||
so.at.x - imperialWidth / 2,
|
||||
so.at.y + imperialHeight / 2
|
||||
)
|
||||
points.__scaleboxImperialBottomRight = new Point(
|
||||
so.at.x + imperialWidth / 2,
|
||||
so.at.y + imperialHeight / 2
|
||||
)
|
||||
// Text anchor points
|
||||
points.__scaleboxLead = new Point(so.at.x - 45 * scale, so.at.y - 15 * scale)
|
||||
points.__scaleboxTitle = points.__scaleboxLead.shift(-90, 10 * scale)
|
||||
points.__scaleboxText = points.__scaleboxTitle.shift(-90, 12 * scale)
|
||||
points.__scaleboxLink = points.__scaleboxText.shift(-90, 5 * scale)
|
||||
points.__scaleboxMetric = new Point(so.at.x, so.at.y + 20 * scale)
|
||||
points.__scaleboxImperial = new Point(so.at.x, so.at.y + 24 * scale)
|
||||
// Rotation
|
||||
if (so.rotate) {
|
||||
so.rotate = Number(so.rotate)
|
||||
let toRotate = [
|
||||
'__scaleboxMetricTopLeft',
|
||||
'__scaleboxMetricTopRight',
|
||||
'__scaleboxMetricBottomLeft',
|
||||
'__scaleboxMetricBottomRight',
|
||||
'__scaleboxImperialTopLeft',
|
||||
'__scaleboxImperialTopRight',
|
||||
'__scaleboxImperialBottomLeft',
|
||||
'__scaleboxImperialBottomRight',
|
||||
'__scaleboxLead',
|
||||
'__scaleboxTitle',
|
||||
'__scaleboxText',
|
||||
'__scaleboxLink',
|
||||
'__scaleboxMetric',
|
||||
'__scaleboxImperial',
|
||||
]
|
||||
for (let pid of toRotate) points[pid] = points[pid].rotate(so.rotate, so.at)
|
||||
for (let pid of toRotate.slice(8)) {
|
||||
points[pid].attributes.set(
|
||||
'data-text-transform',
|
||||
`rotate(${so.rotate * -1}, ${points[pid].x}, ${points[pid].y})`
|
||||
)
|
||||
}
|
||||
}
|
||||
// Paths
|
||||
paths.__scaleboxImperial = new Path()
|
||||
.attr('class', 'scalebox imperial fill-current')
|
||||
.move(points.__scaleboxImperialTopLeft)
|
||||
.line(points.__scaleboxImperialBottomLeft)
|
||||
.line(points.__scaleboxImperialBottomRight)
|
||||
.line(points.__scaleboxImperialTopRight)
|
||||
.close()
|
||||
paths.__scaleboxMetric = new Path()
|
||||
.attr('class', 'scalebox metric fill-bg')
|
||||
.move(points.__scaleboxMetricTopLeft)
|
||||
.line(points.__scaleboxMetricBottomLeft)
|
||||
.line(points.__scaleboxMetricBottomRight)
|
||||
.line(points.__scaleboxMetricTopRight)
|
||||
.close()
|
||||
// Lead
|
||||
points.__scaleboxLead = points.__scaleboxLead
|
||||
.attr('data-text', so.lead || 'FreeSewing')
|
||||
.attr('data-text-class', 'text-sm')
|
||||
// Title
|
||||
if (so.title) points.__scaleboxTitle.attributes.set('data-text', so.title)
|
||||
else {
|
||||
let name = store.data?.name || 'No Name'
|
||||
if (name.indexOf('@freesewing/') !== -1) name = name.replace('@freesewing/', '')
|
||||
points.__scaleboxTitle = points.__scaleboxTitle
|
||||
.attr('data-text', name)
|
||||
.attr('data-text', 'v' + (store.data?.version || 'No Version'))
|
||||
}
|
||||
points.__scaleboxTitle.attributes.add('data-text-class', 'text-lg')
|
||||
// Text
|
||||
if (typeof so.text === 'string') {
|
||||
points.__scaleboxText.attr('data-text', so.text)
|
||||
} else {
|
||||
points.__scaleboxText.attr('data-text', 'supportFreesewingBecomeAPatron')
|
||||
points.__scaleboxLink = points.__scaleboxLink
|
||||
.attr('data-text', 'freesewing.org/patrons/join')
|
||||
.attr('data-text-class', 'text-sm fill-note')
|
||||
}
|
||||
points.__scaleboxText.attr('data-text-class', 'text-xs').attr('data-text-lineheight', 4)
|
||||
// Instructions
|
||||
points.__scaleboxMetric = points.__scaleboxMetric
|
||||
.attr('data-text', 'theWhiteInsideOfThisBoxShouldMeasure')
|
||||
.attr('data-text', `${metricDisplayWidth}`)
|
||||
.attr('data-text', 'x')
|
||||
.attr('data-text', `${metricDisplayHeight}`)
|
||||
.attr('data-text-class', 'text-xs center')
|
||||
points.__scaleboxImperial = points.__scaleboxImperial
|
||||
.attr('data-text', 'theBlackOutsideOfThisBoxShouldMeasure')
|
||||
.attr('data-text', `${imperialDisplayWidth}`)
|
||||
.attr('data-text', 'x')
|
||||
.attr('data-text', `${imperialDisplayHeight}`)
|
||||
.attr('data-text-class', 'text-xs center ')
|
||||
],
|
||||
},
|
||||
miniscale(so, { points, paths, scale, Point, Path }) {
|
||||
// Passing `false` will remove the miniscale
|
||||
if (so === false) {
|
||||
for (const id of [
|
||||
'__miniscaleMetricTopLeft',
|
||||
'__miniscaleMetricTopRight',
|
||||
'__miniscaleMetricBottomRight',
|
||||
'__miniscaleMetricBottomLeft',
|
||||
'__miniscaleImperialTopLeft',
|
||||
'__miniscaleImperialTopRight',
|
||||
'__miniscaleImperialBottomRight',
|
||||
'__miniscaleImperialBottomLeft',
|
||||
'__miniscaleMetric',
|
||||
'__miniscaleImperial',
|
||||
])
|
||||
delete points[id]
|
||||
for (const id of ['__miniscaleMetric', '__miniscaleImperial']) delete paths[id]
|
||||
return true
|
||||
}
|
||||
|
||||
// Convert scale to a value between 0 and 5, inclusive.
|
||||
const scaleIndex = Math.ceil(6 * Math.max(0.1, Math.min(1, scale))) - 1
|
||||
|
||||
// Metric size in mm / display value and imperial size in mm / display value for each scale index.
|
||||
const sizes = [
|
||||
miniscale: [
|
||||
[10, '1cm', 25.4 * 0.375, '⅜″'],
|
||||
[13, '1.3cm', 25.4 * 0.5, '½″'],
|
||||
[16, '1.6cm', 25.4 * 0.625, '⅝″'],
|
||||
[19, '1.9cm', 25.4 * 0.75, '¾″'],
|
||||
[22, '2.2cm', 25.4 * 0.875, '⅞″'],
|
||||
[25, '2.5cm', 25.4 * 1, '1″'],
|
||||
]
|
||||
const m = sizes[scaleIndex][0] / 2
|
||||
const i = sizes[scaleIndex][2] / 2
|
||||
const metricDisplaySize = sizes[scaleIndex][1]
|
||||
const imperialDisplaySize = sizes[scaleIndex][3]
|
||||
// Box points
|
||||
points.__miniscaleMetricTopLeft = new Point(so.at.x - m, so.at.y - m)
|
||||
points.__miniscaleMetricTopRight = new Point(so.at.x + m, so.at.y - m)
|
||||
points.__miniscaleMetricBottomLeft = new Point(so.at.x - m, so.at.y + m)
|
||||
points.__miniscaleMetricBottomRight = new Point(so.at.x + m, so.at.y + m)
|
||||
points.__miniscaleImperialTopLeft = new Point(so.at.x - i, so.at.y - i)
|
||||
points.__miniscaleImperialTopRight = new Point(so.at.x + i, so.at.y - i)
|
||||
points.__miniscaleImperialBottomLeft = new Point(so.at.x - i, so.at.y + i)
|
||||
points.__miniscaleImperialBottomRight = new Point(so.at.x + i, so.at.y + i)
|
||||
// Text anchor points
|
||||
points.__miniscaleMetric = new Point(so.at.x, so.at.y - 2 * scale)
|
||||
points.__miniscaleImperial = new Point(so.at.x, so.at.y + 8 * scale)
|
||||
// Rotation
|
||||
if (so.rotate) {
|
||||
so.rotate = Number(so.rotate)
|
||||
let toRotate = [
|
||||
'__miniscaleMetricTopLeft',
|
||||
'__miniscaleMetricTopRight',
|
||||
'__miniscaleMetricBottomLeft',
|
||||
'__miniscaleMetricBottomRight',
|
||||
'__miniscaleImperialTopLeft',
|
||||
'__miniscaleImperialTopRight',
|
||||
'__miniscaleImperialBottomLeft',
|
||||
'__miniscaleImperialBottomRight',
|
||||
'__miniscaleMetric',
|
||||
'__miniscaleImperial',
|
||||
]
|
||||
for (const pid of toRotate) points[pid] = points[pid].rotate(so.rotate, so.at)
|
||||
for (const pid of toRotate.slice(8)) {
|
||||
points[pid].attributes.set(
|
||||
],
|
||||
}
|
||||
|
||||
/*
|
||||
* This removes a given macro type
|
||||
*/
|
||||
const removeScaleAnnotation = function (id = false, { paths, points, store, part }, type) {
|
||||
if (!id) id = type
|
||||
const both = store.get(['parts', part.name, 'macros', type, 'ids', id], { paths: {}, points: {} })
|
||||
for (const pid of Object.values(both.points)) delete points[pid]
|
||||
for (const pid of Object.values(both.paths)) delete paths[pid]
|
||||
}
|
||||
|
||||
/*
|
||||
* The scalebox macro
|
||||
*/
|
||||
const scalebox = function (config, { store, points, paths, scale, Point, Path, complete, part }) {
|
||||
/*
|
||||
* Don't add a title 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,
|
||||
id: 'scalebox',
|
||||
...config,
|
||||
classes: macroDefaults.classes,
|
||||
}
|
||||
if (config.classes) mc.classes = { ...mc.classes, ...config.classes }
|
||||
|
||||
/*
|
||||
* Figure out what size to use
|
||||
* We convert scale to a value between 0 and 9, inclusive.
|
||||
* Then pick the right size from the sizes[units] array.
|
||||
* Array holds width, height, displayWidth, displayHeight
|
||||
*/
|
||||
const scaleIndex = Math.round(10 * Math.max(0.1, Math.min(1, scale))) - 1
|
||||
const [mw, mh, mdw, mdh] = sizes.scalebox.metric[scaleIndex]
|
||||
const [iw, ih, idw, idh] = sizes.scalebox.imperial[scaleIndex]
|
||||
|
||||
/*
|
||||
* Make sure mc.at is a Point instance
|
||||
*/
|
||||
if (!mc.at || typeof mc.at.attr !== 'function') {
|
||||
log.warn(`Scalebox macro called without a valid at point. Using (0,0) for at.`)
|
||||
mc.from = new Point(0, 0)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the list of IDs
|
||||
*/
|
||||
const ids = getIds(
|
||||
[
|
||||
'metric',
|
||||
'imperial',
|
||||
'textLead',
|
||||
'textMetric',
|
||||
'textImperial',
|
||||
'textTitle',
|
||||
'textText',
|
||||
'textLink',
|
||||
],
|
||||
mc.id,
|
||||
'scalebox'
|
||||
)
|
||||
|
||||
/*
|
||||
* Box points (no need to add these to the part)
|
||||
*/
|
||||
const box = {
|
||||
mtl: new Point(mc.at.x - mw / 2, mc.at.y - mh / 2),
|
||||
mtr: new Point(mc.at.x + mw / 2, mc.at.y - mh / 2),
|
||||
mbl: new Point(mc.at.x - mw / 2, mc.at.y + mh / 2),
|
||||
mbr: new Point(mc.at.x + mw / 2, mc.at.y + mh / 2),
|
||||
itl: new Point(mc.at.x - iw / 2, mc.at.y - ih / 2),
|
||||
itr: new Point(mc.at.x + iw / 2, mc.at.y - ih / 2),
|
||||
ibl: new Point(mc.at.x - iw / 2, mc.at.y + ih / 2),
|
||||
ibr: new Point(mc.at.x + iw / 2, mc.at.y + ih / 2),
|
||||
}
|
||||
|
||||
/*
|
||||
* Text points
|
||||
*/
|
||||
const text = {
|
||||
lead: new Point(mc.at.x - 45 * scale, mc.at.y - 15 * scale),
|
||||
metric: new Point(mc.at.x, mc.at.y + 20 * scale),
|
||||
imperial: new Point(mc.at.x, mc.at.y + 24 * scale),
|
||||
}
|
||||
text.title = text.lead.shift(-90, 10 * scale)
|
||||
text.text = text.title.shift(-90, 12 * scale)
|
||||
text.link = text.text.shift(-90, 5 * scale)
|
||||
|
||||
/*
|
||||
* Handle rotation if needed
|
||||
*/
|
||||
if (mc.rotate) {
|
||||
mc.rotate = Number(mc.rotate)
|
||||
for (const pid in box) box[pid] = box[pid].rotate(mc.rotate, mc.at)
|
||||
for (const pid in text) {
|
||||
text[pid] = text[pid]
|
||||
.rotate(mc.rotate, mc.at)
|
||||
.attr(
|
||||
'data-text-transform',
|
||||
`rotate(${so.rotate * -1}, ${points[pid].x}, ${points[pid].y})`
|
||||
`rotate(${mc.rotate * -1}, ${text[pid].x}, ${text[pid].y})`,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
// Paths
|
||||
paths.__miniscaleImperial = new Path()
|
||||
|
||||
/*
|
||||
* Draw the imperial box
|
||||
*/
|
||||
paths[ids.imperial] = new Path()
|
||||
.attr('class', 'scalebox imperial fill-current')
|
||||
.move(points.__miniscaleImperialTopLeft)
|
||||
.line(points.__miniscaleImperialBottomLeft)
|
||||
.line(points.__miniscaleImperialBottomRight)
|
||||
.line(points.__miniscaleImperialTopRight)
|
||||
.move(box.itl)
|
||||
.line(box.ibl)
|
||||
.line(box.ibr)
|
||||
.line(box.itr)
|
||||
.line(box.itl)
|
||||
.close()
|
||||
paths.__miniscaleMetric = new Path()
|
||||
|
||||
/*
|
||||
* Draw the metric box
|
||||
*/
|
||||
paths[ids.metric] = new Path()
|
||||
.attr('class', 'scalebox metric fill-bg')
|
||||
.move(points.__miniscaleMetricTopLeft)
|
||||
.line(points.__miniscaleMetricBottomLeft)
|
||||
.line(points.__miniscaleMetricBottomRight)
|
||||
.line(points.__miniscaleMetricTopRight)
|
||||
.move(box.mtl)
|
||||
.line(box.mbl)
|
||||
.line(box.mbr)
|
||||
.line(box.mtr)
|
||||
.line(box.mtl)
|
||||
.close()
|
||||
// Text
|
||||
points.__miniscaleMetric = points.__miniscaleMetric
|
||||
.attr('data-text', `${metricDisplaySize} x ${metricDisplaySize}`)
|
||||
.attr('data-text-class', 'text-xs center')
|
||||
points.__miniscaleImperial = points.__miniscaleImperial
|
||||
.attr('data-text', `${imperialDisplaySize} x ${imperialDisplaySize}`)
|
||||
.attr('data-text-class', 'text-xs center ')
|
||||
},
|
||||
|
||||
/*
|
||||
* Add lead text to the part points
|
||||
*/
|
||||
points[ids.textLead] = text.lead
|
||||
.addText(mc.lead || 'FreeSewing', mc.classes.lead)
|
||||
.attr('data-text-class', 'text-sm')
|
||||
|
||||
/*
|
||||
* Figure out what title to use, and add the title text to the part points
|
||||
*/
|
||||
let title = mc.title
|
||||
if (!title) {
|
||||
title = store.data?.name || 'No Name'
|
||||
if (title.indexOf('@freesewing/') !== -1) title = title.replace('@freesewing/', '')
|
||||
}
|
||||
points[ids.textTitle] = text.title
|
||||
.addText(title, mc.classes.title)
|
||||
.attr('data-text', 'v' + (store.data?.version || 'No Version'))
|
||||
|
||||
/*
|
||||
* Add text text to the part points
|
||||
*/
|
||||
points[ids.textText] = text.text.addText(
|
||||
typeof mc.text === 'string' ? mc.text : 'supportFreesewingBecomeAPatron',
|
||||
mc.classes.text
|
||||
)
|
||||
|
||||
/*
|
||||
* Add link text to the part points
|
||||
*/
|
||||
points[ids.textLink] = text.link
|
||||
.addText('freesewing.org/patrons/join', mc.classes.link)
|
||||
.attr('data-text-lineheight', 4)
|
||||
|
||||
/*
|
||||
* Add metric instructions text to the part points
|
||||
*/
|
||||
points[ids.textMetric] = text.metric
|
||||
.attr('data-text', 'theWhiteInsideOfThisBoxShouldMeasure')
|
||||
.attr('data-text', mdw)
|
||||
.attr('data-text', 'x')
|
||||
.attr('data-text', mdh)
|
||||
.attr('data-text-class', mc.classes.metric)
|
||||
|
||||
/*
|
||||
* Add imperial instructions text to the part points
|
||||
*/
|
||||
points[ids.textImperial] = text.imperial
|
||||
.attr('data-text', 'theBlackOutsideOfThisBoxShouldMeasure')
|
||||
.attr('data-text', idw)
|
||||
.attr('data-text', 'x')
|
||||
.attr('data-text', idh)
|
||||
.attr('data-text-class', mc.classes.imperial)
|
||||
|
||||
/*
|
||||
* Store all IDs in the store so we can remove this macro with rmscaleboc
|
||||
*/
|
||||
store.set(['parts', part.name, 'macros', 'scalebox', 'ids', mc.id], {
|
||||
points: {
|
||||
textLead: ids.textLead,
|
||||
textMetric: ids.textMetric,
|
||||
textImperial: ids.textImperial,
|
||||
textTitle: ids.textTitle,
|
||||
textText: ids.textText,
|
||||
textLink: ids.textLink,
|
||||
},
|
||||
paths: {
|
||||
metric: ids.metric,
|
||||
imperial: ids.imperial,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* The miniscale macro
|
||||
*/
|
||||
const miniscale = function (config, { points, paths, scale, Point, Path, part, complete, store }) {
|
||||
/*
|
||||
* Don't add a title 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,
|
||||
id: 'miniscale',
|
||||
...config,
|
||||
classes: macroDefaults.classes,
|
||||
}
|
||||
if (config.classes) mc.classes = { ...mc.classes, ...config.classes }
|
||||
|
||||
/*
|
||||
* Figure out what size to use
|
||||
* We convert scale to a value between 0 and 5, inclusive.
|
||||
* Then pick the right size from the sizes.miniscale array.
|
||||
* Array holds metricSize, metricDisplaySize, imperialSize, imperialDisplaySize
|
||||
*/
|
||||
const scaleIndex = Math.ceil(6 * Math.max(0.1, Math.min(1, scale))) - 1
|
||||
const [ms, mds, is, imds] = sizes.miniscale[scaleIndex]
|
||||
|
||||
/*
|
||||
* Make sure mc.at is a Point instance
|
||||
*/
|
||||
if (!mc.at || typeof mc.at.attr !== 'function') {
|
||||
log.warn(`Scalebox macro called without a valid at point. Using (0,0) for at.`)
|
||||
mc.from = new Point(0, 0)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the list of IDs
|
||||
*/
|
||||
const ids = getIds(['metric', 'imperial', 'textMetric', 'textImperial'], mc.id, 'miniscale')
|
||||
|
||||
/*
|
||||
* Box points (no need to add these to the part)
|
||||
*/
|
||||
const box = {
|
||||
mtl: new Point(mc.at.x - ms / 2, mc.at.y - ms / 2),
|
||||
mtr: new Point(mc.at.x + ms / 2, mc.at.y - ms / 2),
|
||||
mbl: new Point(mc.at.x - ms / 2, mc.at.y + ms / 2),
|
||||
mbr: new Point(mc.at.x + ms / 2, mc.at.y + ms / 2),
|
||||
itl: new Point(mc.at.x - is / 2, mc.at.y - is / 2),
|
||||
itr: new Point(mc.at.x + is / 2, mc.at.y - is / 2),
|
||||
ibl: new Point(mc.at.x - is / 2, mc.at.y + is / 2),
|
||||
ibr: new Point(mc.at.x + is / 2, mc.at.y + is / 2),
|
||||
}
|
||||
|
||||
/*
|
||||
* Text points
|
||||
*/
|
||||
const text = {
|
||||
metric: new Point(mc.at.x, mc.at.y - 2 * scale),
|
||||
imperial: new Point(mc.at.x, mc.at.y + 8 * scale),
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle rotation if needed
|
||||
*/
|
||||
if (mc.rotate) {
|
||||
mc.rotate = Number(mc.rotate)
|
||||
for (const pid in box) box[pid] = box[pid].rotate(mc.rotate, mc.at)
|
||||
for (const pid in text) {
|
||||
text[pid] = text[pid]
|
||||
.rotate(mc.rotate, mc.at)
|
||||
.attr(
|
||||
'data-text-transform',
|
||||
`rotate(${mc.rotate * -1}, ${text[pid].x}, ${text[pid].y})`,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw the imperial box
|
||||
*/
|
||||
paths[ids.imperial] = new Path()
|
||||
.attr('class', 'scalebox imperial fill-current')
|
||||
.move(box.itl)
|
||||
.line(box.ibl)
|
||||
.line(box.ibr)
|
||||
.line(box.itr)
|
||||
.line(box.itl)
|
||||
.close()
|
||||
|
||||
/*
|
||||
* Draw the metric box
|
||||
*/
|
||||
paths[ids.metric] = new Path()
|
||||
.attr('class', 'scalebox metric fill-bg')
|
||||
.move(box.mtl)
|
||||
.line(box.mbl)
|
||||
.line(box.mbr)
|
||||
.line(box.mtr)
|
||||
.line(box.mtl)
|
||||
.close()
|
||||
|
||||
/*
|
||||
* Add metric text to the part points
|
||||
*/
|
||||
points[ids.textMetric] = text.metric.addText(`${mds} x ${mds}`, mc.classes.metric)
|
||||
|
||||
/*
|
||||
* Add imperial text to the part points
|
||||
*/
|
||||
points[ids.textImperial] = text.imperial.addText(`${imds} x ${imds}`, mc.classes.imperial)
|
||||
|
||||
/*
|
||||
* Store all IDs in the store so we can remove this macro with rmscaleboc
|
||||
*/
|
||||
store.set(['parts', part.name, 'macros', 'miniscale', 'ids', mc.id], {
|
||||
points: {
|
||||
textMetric: ids.textMetric,
|
||||
textImperial: ids.textImperial,
|
||||
},
|
||||
paths: {
|
||||
metric: ids.metric,
|
||||
imperial: ids.imperial,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Export macros
|
||||
export const scaleboxMacros = {
|
||||
scalebox,
|
||||
miniscale,
|
||||
rmscalebox: (id, props) => removeScaleAnnotation(id, props, 'scalebox'),
|
||||
rmminiscale: (id, props) => removeScaleAnnotation(id, props, 'miniscale'),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue