import { TextOnPath } from './text.mjs'
import { getProps } from './utils.mjs'
import { round, formatMm } from 'shared/utils.mjs'
import { RawSpan } from 'shared/components/raw-span.mjs'
export const pointCoords = (point) =>
point ? `[ ${round(point.x, 2)}, ${round(point.y, 2)} ]` : null
export const Tr = ({ children }) =>
{children}
export const KeyTd = ({ children }) => {children}: |
export const ValTd = ({ children }) => {children} |
export const TextAlongPath = ({ id, size, txt }) => (
{txt}
)
export const PointCircle = ({ point, size, className = 'stroke-neutral-content' }) => (
)
const CpCircle = ({ point, className = 'fill-lining no-stroke' }) => (
)
const EpCircle = ({ point, className = 'fill-note no-stroke' }) => (
)
const pathDimensions = (from, to, cp1 = false, cp2 = false, path = false) => {
const topLeft = {
x: to.x < from.x ? to.x : from.x,
y: to.y < from.y ? to.y : from.y,
}
const bottomRight = {
x: to.x > from.x ? to.x : from.x,
y: to.y > from.y ? to.y : from.y,
}
let bbox = false
// Deal with curves
if (cp1 && cp2) {
if (cp1.x < topLeft.x) topLeft.x = cp1.x
if (cp2.x < topLeft.x) topLeft.x = cp2.x
if (cp1.x > bottomRight.x) bottomRight.x = cp1.x
if (cp2.x > bottomRight.x) bottomRight.x = cp2.x
if (cp1.y < topLeft.y) topLeft.y = cp1.y
if (cp2.y < topLeft.y) topLeft.y = cp2.y
if (cp1.y > bottomRight.y) bottomRight.y = cp1.y
if (cp2.y > bottomRight.y) bottomRight.y = cp2.y
// This undocumented core methods returns the curve's bounding box
bbox = path.bbox()
}
const w = bottomRight.x - topLeft.x
const h = bottomRight.y - topLeft.y
const size = w > h ? w : h
return {
topLeft,
bottomRight,
w,
h,
size,
bbox,
}
}
export const Defs = () => (
)
export const svgProps = {
xmlns: 'http://www.w3.org/2000/svg',
xmlnsSvg: 'http://www.w3.org/2000/svg',
xmlnsXlink: 'http://www.w3.org/1999/xlink',
style: { maxHeight: 'inherit', strokeLinecap: 'round', strokeLinejoin: 'round' },
}
const Line = (props) => {
const ops = props.path.ops
const from = ops[0].to
const to = ops[1].to
const { topLeft, bottomRight, w, h, size } = pathDimensions(from, to)
const id = `${props.partName}_${props.pathName}_${props.i}`
const xyProps = {
className: 'stroke-neutral-content',
strokeOpacity: '0.5',
fill: 'none',
strokeWidth: size / 300,
}
return (
)
}
const Curve = (props) => {
const ops = props.path.ops
const from = ops[0].to
const { to, cp1, cp2 } = ops[1]
const { topLeft, w, h, size, bbox } = pathDimensions(from, to, cp1, cp2, props.path)
const id = `${props.partName}_${props.pathName}_${props.i}`
const cpProps = {
className: 'stroke-success',
strokeOpacity: '0.85',
fill: 'none',
strokeWidth: size / 300,
}
const xyProps = {
...cpProps,
strokeOpacity: '0.5',
className: 'stroke-neutral-content',
markerEnd: 'url(#arrowTo)',
markerStart: 'url(#arrowFrom)',
}
return (
)
}
const MiniPath = (props) => {
const bbox = props.path.bbox()
const id = `${props.partName}_${props.pathName}_mini}`
const w = bbox.bottomRight.x - bbox.topLeft.x
const h = bbox.bottomRight.y - bbox.topLeft.y
const size = w > h ? w : h
const xyProps = {
fill: 'none',
strokeWidth: size / 300,
strokeOpacity: '0.5',
className: 'stroke-neutral-content',
markerEnd: 'url(#arrowTo)',
markerStart: 'url(#arrowFrom)',
}
return (
)
}
const lineInfo = (props) => (
Line info
From
{pointCoords(props.path.ops[0].to)}
To
{pointCoords(props.path.ops[1].to)}
Length
{formatMm(props.path.length(), props.gist.units, 'notags')}
Width
Height
Part
{props.partName}
Draw Op
{props.i}/{props.ops.length}
)
const XrayLine = (props) => (
<>
{
evt.stopPropagation()
props.showInfo(lineInfo(props))
}}
/>
>
)
const curveInfo = (props) => (
Curve info
From
{pointCoords(props.path.ops[0].to)}
Cp1
{pointCoords(props.path.ops[1].cp1)}
Cp2
{pointCoords(props.path.ops[1].cp2)}
To
{pointCoords(props.path.ops[1].to)}
Length
Width
Height
Part
{props.partName}
Draw Op
{props.i}/{props.ops.length}
)
export const Attributes = ({ list }) =>
list ? (
{Object.keys(list).map((key) => (
-
{key}: {list[key]}
))}
) : null
export const pathInfo = (props) => {
const bbox = props.path.bbox()
return (
Path info
Name
{props.pathName}
Length
Width
Height
Top Left
{pointCoords(bbox.topLeft)}
Bottom Right
{pointCoords(bbox.bottomRight)}
Part
{props.partName}
Attributes
{props.path.ops.map((op, i) => (
{i}
))}
)
}
const PathOp = ({ op }) => {
if (op.type === 'move')
return (
Move to {pointCoords(op.to)}
)
else if (op.type === 'line')
return (
Line to {pointCoords(op.to)}
)
else if (op.type === 'curve')
return (
Curve to {pointCoords(op.to)}
Cp1: {pointCoords(op.cp1)}
Cp2: {pointCoords(op.cp2)}
)
else if (op.type === 'noop') return NOOP
else if (op.type === 'close') return Close
else return FIXME: unknown path operation type: {op.type}
}
const XrayCurve = (props) => {
const from = props.path.ops[0].to
const { cp1, cp2, to } = props.path.ops[1]
return (
<>
{
evt.stopPropagation()
props.showInfo(curveInfo(props))
}}
/>
>
)
}
const XrayPath = (props) => {
const classes = props.path.attributes.get('class')
if (typeof classes === 'string' && classes.includes('noxray')) return null
const ops = props.path.divide()
return (
{
evt.preventDefault()
props.showInfo(pathInfo(props))
}}
markerStart="none"
markerEnd="none"
/>
{ops.length > 0
? ops.map((op, i) =>
op.ops[1].type === 'curve' ? (
) : (
)
)
: null}
)
}
export const Path = (props) => {
const { path, partName, pathName } = props
if (path.hidden) return null
const output = []
const pathId = 'path-' + partName + '-' + pathName
let d = ''
try {
d = path.asPathstring()
} catch (err) {
// Bail out
console.log(`Failed to generate pathstring for path ${pathId} in part ${partName}`, err)
return null
}
output.push()
if (path.attributes.get('data-text'))
output.push()
if (props.gist._state?.xray?.enabled) output.push()
return output
}