@things-factory/figure-ui 10.1.203 → 10.1.205
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/modeller/canvas.ts +91 -9
- package/client/modeller/editor-styles.ts +7 -22
- package/client/modeller/editor.ts +176 -145
- package/client/modeller/fasten-form.ts +91 -9
- package/client/modeller/figure-fasten-dialog.ts +42 -9
- package/client/modeller/figure-fasten-drawing.ts +233 -12
- package/client/modeller/figure-section-editor.ts +6 -6
- package/client/modeller/figure-slot-layout-panel.ts +1 -1
- package/client/modeller/gizmo.ts +12 -1
- package/client/modeller/links.ts +48 -6
- package/client/modeller/section-drawing.ts +7 -7
- package/client/modeller/size-drag.ts +112 -0
- package/client/modeller/slot-layout-host.ts +3 -3
- package/client/modeller/stage-model.ts +6 -9
- package/client/pages/figure-modeller-page.ts +1 -4
- package/dist-client/modeller/canvas.d.ts +24 -3
- package/dist-client/modeller/canvas.js +96 -11
- package/dist-client/modeller/canvas.js.map +1 -1
- package/dist-client/modeller/editor-styles.js +7 -22
- package/dist-client/modeller/editor-styles.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +28 -32
- package/dist-client/modeller/editor.js +176 -153
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/fasten-form.d.ts +36 -3
- package/dist-client/modeller/fasten-form.js +86 -8
- package/dist-client/modeller/fasten-form.js.map +1 -1
- package/dist-client/modeller/figure-fasten-dialog.d.ts +17 -3
- package/dist-client/modeller/figure-fasten-dialog.js +47 -10
- package/dist-client/modeller/figure-fasten-dialog.js.map +1 -1
- package/dist-client/modeller/figure-fasten-drawing.d.ts +33 -1
- package/dist-client/modeller/figure-fasten-drawing.js +235 -11
- package/dist-client/modeller/figure-fasten-drawing.js.map +1 -1
- package/dist-client/modeller/figure-section-editor.d.ts +3 -3
- package/dist-client/modeller/figure-section-editor.js +4 -4
- package/dist-client/modeller/figure-section-editor.js.map +1 -1
- package/dist-client/modeller/figure-slot-layout-panel.js +1 -1
- package/dist-client/modeller/figure-slot-layout-panel.js.map +1 -1
- package/dist-client/modeller/gizmo.d.ts +12 -1
- package/dist-client/modeller/gizmo.js +8 -0
- package/dist-client/modeller/gizmo.js.map +1 -1
- package/dist-client/modeller/links.d.ts +14 -2
- package/dist-client/modeller/links.js +42 -4
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/section-drawing.d.ts +3 -4
- package/dist-client/modeller/section-drawing.js +10 -9
- package/dist-client/modeller/section-drawing.js.map +1 -1
- package/dist-client/modeller/size-drag.d.ts +38 -0
- package/dist-client/modeller/size-drag.js +85 -0
- package/dist-client/modeller/size-drag.js.map +1 -0
- package/dist-client/modeller/slot-layout-host.d.ts +1 -3
- package/dist-client/modeller/slot-layout-host.js +3 -3
- package/dist-client/modeller/slot-layout-host.js.map +1 -1
- package/dist-client/modeller/stage-model.d.ts +5 -7
- package/dist-client/modeller/stage-model.js +6 -6
- package/dist-client/modeller/stage-model.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.d.ts +0 -2
- package/dist-client/pages/figure-modeller-page.js +1 -6
- package/dist-client/pages/figure-modeller-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/test/align.test.ts +7 -11
- package/test/browser/acceptance-page.js +10 -0
- package/test/browser/editing.check.mjs +17 -13
- package/test/browser/links-page.js +2 -2
- package/test/browser/links.check.mjs +94 -56
- package/test/browser/modeller-page.js +30 -18
- package/test/browser/modeller-revision.check.mjs +39 -0
- package/test/browser/modeller.check.mjs +32 -10
- package/test/browser/screen-page.js +0 -2
- package/test/browser/screen.check.mjs +11 -13
- package/test/browser/section.check.mjs +2 -2
- package/test/fasten-form.test.ts +82 -2
- package/test/gizmo.test.ts +13 -15
- package/test/links.test.ts +8 -3
- package/test/resize-with-placement.test.ts +14 -13
- package/test/revision.test.ts +3 -2
- package/test/section-editor.test.ts +9 -10
- package/test/size-drag.test.ts +114 -0
- package/test/slot-layout-host.test.ts +13 -8
- package/translations/en.json +25 -22
- package/translations/es.json +25 -22
- package/translations/ja.json +25 -22
- package/translations/ko.json +25 -22
- package/translations/ms.json +25 -22
- package/translations/zh.json +25 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-fasten-dialog.js","sourceRoot":"","sources":["../../client/modeller/figure-fasten-dialog.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/popup/ox-popup-actions.js'\nimport { CommonPopupStyles } from '@operato/styles'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\n\nimport './figure-fasten-drawing.js'\nimport type { FastenChange } from './figure-fasten-drawing.js'\nimport { turnsInPlace, type FastenMode } from './fasten-geometry.js'\nimport {\n aimFasten,\n fastenChanged,\n fastenDetailWordsOf,\n fastenFormOf,\n fastenPlanOf,\n fastenSentenceOf,\n fastenTargetsOf,\n type FastenForm\n} from './fasten-form.js'\nimport { fieldWordsOf, hasInstanceSize, heldBy, mountingPlaneOf, type Alignment, type Axis } from './links.js'\nimport type { FigureRevision } from './revision.js'\n\n/** The target list's entry for the plane the figure stands by. */\nconst PLANE = '__plane'\n\n/**\n * 붙이기 창: what the selected part is fastened to, on which face, how (user 2026-10-17: 「속성에는 심플하고 직관적인\n * 결과 위주로, 편집은 팝업에서 넓은 공간을 써서」). The editor stands it over the side panel with its title and close,\n * where the canvas stays in sight (2026-10-19: the standard popup, always modal, hid the 3D it was choosing for).\n *\n * Everything chosen here is tried, not done: the command it comes to is told to the editor as it changes\n * (`preview-command`), and the canvas draws it. 「적용」 sends it once (`fasten-apply`), one step of the history;\n * 「취소」 and Esc close it with nothing written (`fasten-cancel`). A row of the target list under the pointer or the\n * arrows asks the canvas to light that part (`fasten-hover`). The window is the only one telling the preview while it\n * is open; the editor keeps the panel quiet.\n */\n@customElement('figure-fasten-dialog')\nexport class FigureFastenDialog extends localize(i18next)(LitElement) {\n static styles = [\n SidePanelStyles,\n CommonPopupStyles,\n css`\n :host {\n display: grid;\n gap: 16px;\n padding: var(--popup-padding, 16px);\n overflow: auto;\n }\n /* The result in one line, at the top: it changes with every choice below it. */\n p[fasten-sentence] {\n margin: 0;\n font-size: var(--ui-t-body, 13px);\n font-weight: 600;\n }\n div[question] {\n display: grid;\n align-content: start;\n gap: 6px;\n }\n h4 {\n margin: 0;\n font-size: var(--ui-t-small, 11.5px);\n font-weight: 600;\n color: var(--md-sys-color-on-surface-variant);\n }\n /* The chips are part names, identifiers: shown as they are written, not capitalized as filter words are. */\n ox-input-select-buttons {\n --ox-input-select-buttons-label-text-transform: none;\n }\n p[loops] {\n margin: 0;\n }\n details[fasten-detail] {\n margin: 0;\n }\n details[fasten-detail] > div[form] {\n margin-top: 8px;\n max-width: 320px;\n }\n span[fasten-summary] {\n opacity: 0.8;\n }\n ul[preview-words] {\n margin: 0;\n padding: 8px 12px 8px 26px;\n border-radius: 6px;\n background: var(--md-sys-color-surface-container, #8881);\n display: grid;\n gap: 4px;\n }\n p[preview-words] {\n margin: 0;\n padding: 8px 12px;\n border-radius: 6px;\n background: var(--md-sys-color-surface-container, #8881);\n }\n p[error] {\n margin: 0;\n color: var(--md-sys-color-error);\n }\n /* 취소 · 적용 stay in sight at the window's foot when what is above them is taller than the panel. */\n ox-popup-actions {\n position: sticky;\n bottom: calc(-1 * var(--popup-padding, 16px));\n margin-bottom: calc(-1 * var(--popup-padding, 16px));\n padding-bottom: var(--popup-padding, 16px);\n background: var(--md-sys-color-surface-container-lowest);\n }\n `\n ]\n\n /** The figure at the version on screen. */\n @property({ attribute: false }) revision?: FigureRevision\n /** The part being fastened. */\n @property() partId = ''\n @property({ type: Boolean }) locked = false\n /** What the command would do, in words (the editor works it out: `command-preview.ts`). */\n @property({ attribute: false }) previewWords: string[] = []\n /** Why the last 「적용」 was refused, in the editor's words. */\n @property() error = ''\n\n @state() private form?: FastenForm\n /** The command the part's own fastening comes to, as opened: tried unchanged, nothing new is said of it. */\n private opened?: string\n private told = ''\n private loadedFor?: string\n private hovered: string | null = null\n\n willUpdate() {\n /* Opened on what the part has now; another part is another window's. */\n if (this.revision && this.partId && this.partId !== this.loadedFor) {\n this.loadedFor = this.partId\n this.form = fastenFormOf(this.revision, this.partId)\n this.opened = JSON.stringify(fastenPlanOf(this.revision, this.partId, this.form).action ?? null)\n }\n }\n\n async firstUpdated() {\n /* Into the list, on what is chosen, so the arrows go from there. */\n const list = this.renderRoot.querySelector<HTMLElement & { updateComplete?: Promise<unknown> }>(\n 'ox-input-select-buttons'\n )\n await list?.updateComplete\n const chips = list?.shadowRoot?.querySelectorAll<HTMLElement>('md-filter-chip')\n ;([...(chips ?? [])].find(c => c.hasAttribute('selected')) ?? chips?.[0])?.focus()\n }\n\n updated() {\n const plan = this.revision && this.form ? fastenPlanOf(this.revision, this.partId, this.form) : undefined\n const candidate = plan?.action ? { action: plan.action, ...(plan.face ? { face: plan.face } : {}) } : null\n const said = JSON.stringify(candidate)\n if (said === this.told) return\n this.told = said\n this.dispatchEvent(new CustomEvent('preview-command', { detail: candidate, bubbles: true, composed: true }))\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n /* Closed: what it showed goes with it. */\n if (this.told && this.told !== 'null')\n this.dispatchEvent(new CustomEvent('preview-command', { detail: null, bubbles: true, composed: true }))\n this.told = ''\n this.hover(null)\n }\n\n render() {\n const revision = this.revision\n const f = this.form\n if (!revision || !f) return nothing\n const asset = revision.asset\n const held = !!heldBy(asset, this.partId)\n const plan = fastenPlanOf(revision, this.partId, f)\n const planeWord = i18next.t('figure.label.resize-place-' + (asset.placement ?? 'floor'))\n const modes: FastenMode[] = f.toPlane\n ? mountingPlaneOf(asset).facings\n : ['meet', 'flush', ...(turnsInPlace(asset, this.partId) ? (['centre'] as FastenMode[]) : [])]\n const detail = fastenDetailWordsOf(f, (key, params) => i18next.t(key, params))\n const drawing = (show: 'face' | 'how') =>\n html`<figure-fasten-drawing\n show=${show}\n .target=${f.toPlane ? '' : f.target}\n .planeWord=${planeWord}\n .faces=${plan.theirFaces}\n .face=${plan.targetFace}\n .modes=${modes}\n .mode=${plan.mode}\n .view=${plan.view}\n .align=${f.align}\n .alignMm=${f.alignMm}\n .gap=${f.gap}\n .partName=${this.partId}\n ?locked=${this.locked}\n @fasten-change=${(e: CustomEvent<FastenChange>) => (this.form = fastenChanged(revision, this.partId, this.form!, e.detail))}\n ></figure-fasten-drawing>`\n return html`\n ${\n plan.aim\n ? html`<p fasten-sentence role=\"status\">\n ${fastenSentenceOf(f, plan, planeWord, (key, params) => i18next.t(key, params))}\n </p>`\n : html`<p hint fasten-sentence>${i18next.t('figure.text.fasten-target-first')}</p>`\n }\n <div question=\"what\">\n <h4 id=\"what\">${i18next.t('figure.label.fasten-what')}</h4>\n ${this.renderTargets(revision, f, planeWord)}\n </div>\n ${\n plan.aim\n ? html`<div question=\"face\">\n <h4>\n ${\n /* The face asked is the target's, named: the part meets it by its real shape, by no face of its own. */ f.toPlane\n ? i18next.t('figure.label.fasten-face-on-plane', { plane: planeWord })\n : i18next.t('figure.label.fasten-face-on-part', { part: f.target })\n }\n </h4>\n ${drawing('face')}\n </div>\n ${\n modes.length > 1\n ? html`<div question=\"how\">\n <h4>${i18next.t('figure.label.fasten-how')}</h4>\n ${drawing('how')}\n </div>`\n : nothing\n }\n <div question=\"detail\">\n <details fasten-detail>\n <summary>\n ${i18next.t('figure.label.fasten-detail')}${detail.length ? html` · <span fasten-summary>${detail.join(' · ')}</span>` : nothing}\n </summary>\n ${plan.alignRows.length ? this.renderAlignment(plan.alignRows) : nothing}\n <div form>\n <span>${i18next.t('figure.label.gap')}</span>\n <input\n gap\n type=\"number\"\n step=\"any\"\n .value=${f.gapKept !== undefined ? '' : String(f.gap)}\n placeholder=${f.gapKept !== undefined ? i18next.t('figure.label.follows-expression') : ''}\n @change=${(e: Event) => this.set({ gap: Number((e.target as HTMLInputElement).value) || 0, gapKept: undefined })}\n />\n </div>\n </details>\n </div>\n ${/* The one it has, tried unchanged: that it stays where it is goes without saying. */ JSON.stringify(plan.action ?? null) === this.opened ? nothing : this.renderPreviewWords()}`\n : nothing\n }\n ${this.error ? html`<p error role=\"alert\">${this.error}</p>` : nothing}\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" cancel @click=${this.cancel}>${i18next.t('figure.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" apply ?disabled=${this.locked || !plan.action} @click=${this.apply}>\n ${i18next.t(held ? 'figure.button.apply' : 'figure.button.fasten')}\n </md-filled-button>\n </ox-popup-actions>\n `\n }\n\n /**\n * What to fasten to: the plane and the other parts, as the standard choice chips. The arrows move among them and\n * the canvas lights the part under the focus or the pointer; a part hanging from this one is not offered, and why is\n * said under them.\n */\n private renderTargets(revision: FigureRevision, f: FastenForm, planeWord: string) {\n const chosen = f.toPlane ? PLANE : f.target\n const targets = fastenTargetsOf(revision, this.partId)\n const chipOf = (e: Event) =>\n (e.composedPath().find(n => (n as Element).localName === 'md-filter-chip') as Element | undefined)?.getAttribute(\n 'data-value'\n ) ?? null\n return html`<ox-input-select-buttons\n targets\n aria-labelledby=\"what\"\n .options=${[{ value: PLANE, display: planeWord }, ...targets.filter(t => !t.loops).map(t => ({ value: t.part, display: t.part }))]}\n .value=${chosen || undefined}\n ?disabled=${this.locked}\n @change=${(e: CustomEvent) => {\n /* A chip pressed again lets go of it; what to fasten to is always one thing once chosen. */\n if (e.detail) this.aim(e.detail)\n else (e.target as HTMLElement & { value?: string }).value = chosen || undefined\n }}\n @pointerover=${(e: Event) => this.hover(chipOf(e))}\n @pointerleave=${() => this.hover(null)}\n @focusin=${(e: Event) => this.hover(chipOf(e))}\n @keyup=${(e: KeyboardEvent) => {\n /* The arrows move the focus among the chips inside the list, which tells nothing outside it: read where it is. */\n const at = (e.currentTarget as Element).shadowRoot?.activeElement\n if (at?.localName === 'md-filter-chip') this.hover(at.getAttribute('data-value'))\n }}\n ></ox-input-select-buttons>\n ${this.renderLoops(targets.filter(t => t.loops).map(t => t.part))}`\n }\n\n /**\n * The parts that hang from this one, in one line: a line each made a list longer than the chips (2026-10-18, :3300,\n * the robot arm's forearm and the six parts it carries).\n */\n private renderLoops(parts: string[]) {\n if (!parts.length) return nothing\n return html`<p hint loops targets=${parts.join(',')}>\n ${i18next.t('figure.text.target-would-loop', { part: parts.join(', '), mine: this.partId })}\n </p>`\n }\n\n private aim(part: string) {\n if (this.locked || !this.revision || !this.form) return\n const chosen = this.form.toPlane ? PLANE : this.form.target\n if (part === chosen) return\n this.form = aimFasten(this.revision, this.partId, this.form, part === PLANE ? { plane: true } : { part })\n }\n\n /** The part under the pointer or the focus in the list, for the canvas to light; the plane lights nothing. */\n private hover(part: string | null) {\n const lit = part && part !== PLANE ? part : null\n if (lit === this.hovered) return\n this.hovered = lit\n const face =\n lit && this.revision && this.form\n ? fastenPlanOf(this.revision, this.partId, aimFasten(this.revision, this.partId, this.form, { part: lit }))\n .targetFace\n : undefined\n this.dispatchEvent(\n new CustomEvent('fasten-hover', { detail: lit ? { part: lit, face } : null, bubbles: true, composed: true })\n )\n }\n\n private set(change: Partial<FastenForm>) {\n this.form = { ...this.form!, ...change }\n }\n\n /**\n * Where on the target face the part sits, on the axes the drawing cannot set: centred, level with the target's edge on\n * either side, a distance off centre, a share of the figure's size, or the position field it follows.\n */\n private renderAlignment(axes: { axis: Axis; edges: boolean }[]) {\n const f = this.form!\n const set = (axis: Axis, how: Alignment) => this.set({ align: { ...f.align, [axis]: how } })\n const setMm = (axis: Axis, mm: number) => this.set({ alignMm: { ...f.alignMm, [axis]: mm } })\n return html`<div form>\n ${axes.map(({ axis, edges }) => {\n const how =\n f.align[axis] === 'min' || f.align[axis] === 'max'\n ? edges\n ? f.align[axis]!\n : 'centre'\n : (f.align[axis] ?? 'centre')\n return html`<span>${i18next.t('figure.label.align-' + axis)}</span>\n <select @change=${(e: Event) => set(axis, (e.target as HTMLSelectElement).value as Alignment)}>\n <option value=\"centre\" ?selected=${how === 'centre'}>${i18next.t('figure.label.align-centre')}</option>\n ${\n edges\n ? html`<option value=\"min\" ?selected=${how === 'min'}>\n ${i18next.t(`figure.label.align-${axis}-min`)}\n </option>\n <option value=\"max\" ?selected=${how === 'max'}>\n ${i18next.t(`figure.label.align-${axis}-max`)}\n </option>`\n : nothing\n }\n ${\n f.alignInput?.[axis]\n ? html`<option value=\"input\" ?selected=${how === 'input'}>\n ${i18next.t('figure.label.align-input', { field: fieldWordsOf(f.alignInput[axis]!, key => i18next.t(key)) })}\n </option>`\n : nothing\n }\n <option value=\"mm\" ?selected=${how === 'mm'}>${i18next.t('figure.label.align-mm')}</option>\n ${\n this.revision && hasInstanceSize(this.revision.asset, axis)\n ? html`<option value=\"share\" ?selected=${how === 'share'}>\n ${i18next.t('figure.label.align-share')}\n </option>`\n : nothing\n }\n </select>\n ${\n how === 'mm' || how === 'share'\n ? html`<span></span\n ><input\n type=\"number\"\n step=\"any\"\n aria-label=${i18next.t('figure.label.align-mm')}\n .value=${String(f.alignMm[axis] ?? 0)}\n @change=${(e: Event) => setMm(axis, Number((e.target as HTMLInputElement).value) || 0)}\n />`\n : nothing\n }`\n })}\n </div>`\n }\n\n private renderPreviewWords() {\n if (this.previewWords.length === 1) return html`<p preview-words role=\"status\">${this.previewWords[0]}</p>`\n return this.previewWords.length\n ? html`<ul preview-words role=\"status\">\n ${this.previewWords.map(line => html`<li>${line}</li>`)}\n </ul>`\n : nothing\n }\n\n /** Enter applies what is chosen, Esc closes with nothing written; a key the window does not take goes on. */\n connectedCallback() {\n super.connectedCallback()\n this.setAttribute('role', 'dialog')\n this.setAttribute('aria-label', i18next.t('figure.label.fastening'))\n this.addEventListener('keydown', this.onKey)\n }\n\n private onKey = async (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n e.preventDefault()\n this.cancel()\n return\n }\n if (e.key !== 'Enter' || e.isComposing) return\n const path = e.composedPath() as Element[]\n const target = path[0] as HTMLElement\n /* On a chip of the list Enter applies, as it does anywhere in the window; a chip is chosen by Space or a press. */\n const onChip = path.some(n => n.localName === 'ox-input-select-buttons')\n /* A button, a fold or a list of options does what Enter does to it. */\n if (\n !onChip &&\n (target.localName === 'button' ||\n target.localName === 'summary' ||\n target.localName === 'select' ||\n /^md-.*button$/.test(target.localName))\n )\n return\n e.preventDefault()\n e.stopPropagation()\n /* A number typed and Enter: the number first, as leaving the field would take it. */\n if (target.localName === 'input') target.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n await this.updateComplete\n this.apply()\n }\n\n private apply = () => {\n const plan = this.revision && this.form ? fastenPlanOf(this.revision, this.partId, this.form) : undefined\n if (this.locked || !plan?.action) return\n this.dispatchEvent(\n new CustomEvent('fasten-apply', { detail: { action: plan.action }, bubbles: true, composed: true })\n )\n }\n\n private cancel = () => {\n this.dispatchEvent(new CustomEvent('fasten-cancel', { bubbles: true, composed: true }))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-fasten-dialog.js","sourceRoot":"","sources":["../../client/modeller/figure-fasten-dialog.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/popup/ox-popup-actions.js'\nimport { CommonPopupStyles } from '@operato/styles'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\n\nimport './figure-fasten-drawing.js'\nimport type { FastenChange } from './figure-fasten-drawing.js'\nimport { turnsInPlace, type FastenMode } from './fasten-geometry.js'\nimport {\n aimFasten,\n aimFastenAt,\n fastenChanged,\n fastenDetailWordsOf,\n fastenFormOf,\n fastenPlanOf,\n fastenSentenceOf,\n fastenTargetsOf,\n type FastenForm\n} from './fasten-form.js'\nimport { fieldWordsOf, hasInstanceSize, heldBy, mountingPlaneOf, surfaceOf, type Alignment, type Axis } from './links.js'\nimport type { FigureRevision } from './revision.js'\n\n/** The target list's entry for the plane the figure stands by. */\nconst PLANE = '__plane'\n\n/**\n * 붙이기 창: what the selected part is fastened to, on which face, how -- chosen with room to see it, in the standard\n * popup the editor opens (`openPopup`: its title, its close, moved by its head; no backdrop, so the canvas can be\n * pressed while it is open) (user 2026-10-17: 「속성에는 심플하고 직관적인 결과 위주로, 편집은 팝업에서 넓은 공간을\n * 써서」; 2026-10-18: the standard popup, not a window of its own; put back 2026-10-20).\n *\n * Everything chosen here is tried, not done: the command it comes to is told to the editor as it changes\n * (`preview-command`), and the canvas draws it. 「적용」 sends it once (`fasten-apply`), one step of the history;\n * 「취소」 and Esc close it with nothing written (`fasten-cancel`). A row of the target list under the pointer or the\n * arrows asks the canvas to light that part (`fasten-hover`). The window is the only one telling the preview while it\n * is open; the editor keeps the panel quiet.\n */\n@customElement('figure-fasten-dialog')\nexport class FigureFastenDialog extends localize(i18next)(LitElement) {\n static styles = [\n SidePanelStyles,\n CommonPopupStyles,\n css`\n /*\n The popup holds it at its own height and cuts what is past the screen: the window scrolls itself, within the\n screen less the popup's head and margins, 취소 · 적용 kept at its foot (below).\n */\n :host {\n display: grid;\n gap: 16px;\n padding: var(--popup-padding, 16px);\n overflow: auto;\n max-height: calc(100dvh - 32px - 56px);\n }\n /* The result in one line, at the top: it changes with every choice below it. */\n p[fasten-sentence] {\n margin: 0;\n font-size: var(--ui-t-body, 13px);\n font-weight: 600;\n }\n div[question] {\n display: grid;\n align-content: start;\n gap: 6px;\n }\n h4 {\n margin: 0;\n font-size: var(--ui-t-small, 11.5px);\n font-weight: 600;\n color: var(--md-sys-color-on-surface-variant);\n }\n /* The chips are part names, identifiers: shown as they are written, not capitalized as filter words are. */\n ox-input-select-buttons {\n --ox-input-select-buttons-label-text-transform: none;\n }\n p[loops] {\n margin: 0;\n }\n details[fasten-detail] {\n margin: 0;\n }\n details[fasten-detail] > div[form] {\n margin-top: 8px;\n max-width: 320px;\n }\n span[fasten-summary] {\n opacity: 0.8;\n }\n ul[preview-words] {\n margin: 0;\n padding: 8px 12px 8px 26px;\n border-radius: 6px;\n background: var(--md-sys-color-surface-container, #8881);\n display: grid;\n gap: 4px;\n }\n p[preview-words] {\n margin: 0;\n padding: 8px 12px;\n border-radius: 6px;\n background: var(--md-sys-color-surface-container, #8881);\n }\n p[error] {\n margin: 0;\n color: var(--md-sys-color-error);\n }\n /* 취소 · 적용 stay in sight at the window's foot when what is above them is taller than the screen. */\n ox-popup-actions {\n position: sticky;\n bottom: calc(-1 * var(--popup-padding, 16px));\n margin-bottom: calc(-1 * var(--popup-padding, 16px));\n padding-bottom: var(--popup-padding, 16px);\n background: var(--md-sys-color-surface-container-lowest);\n }\n `\n ]\n\n /** The figure at the version on screen. */\n @property({ attribute: false }) revision?: FigureRevision\n /** The part being fastened. */\n @property() partId = ''\n @property({ type: Boolean }) locked = false\n /** What the command would do, in words (the editor works it out: `command-preview.ts`). */\n @property({ attribute: false }) previewWords: string[] = []\n /** Why the last 「적용」 was refused, in the editor's words. */\n @property() error = ''\n\n @state() private form?: FastenForm\n /** Why a press on the canvas aimed at nothing, or only at the part (ADR-0140 stage 4); cleared by the next choice. */\n @state() private aimNote = ''\n /** The command the part's own fastening comes to, as opened: tried unchanged, nothing new is said of it. */\n private opened?: string\n private told = ''\n private loadedFor?: string\n private hovered: string | null = null\n\n willUpdate() {\n /* Opened on what the part has now; another part is another window's. */\n if (this.revision && this.partId && this.partId !== this.loadedFor) {\n this.loadedFor = this.partId\n this.form = fastenFormOf(this.revision, this.partId)\n this.opened = JSON.stringify(fastenPlanOf(this.revision, this.partId, this.form).action ?? null)\n }\n }\n\n async firstUpdated() {\n /* Into the list, on what is chosen, so the arrows go from there. */\n const list = this.renderRoot.querySelector<HTMLElement & { updateComplete?: Promise<unknown> }>(\n 'ox-input-select-buttons'\n )\n await list?.updateComplete\n const chips = list?.shadowRoot?.querySelectorAll<HTMLElement>('md-filter-chip')\n ;([...(chips ?? [])].find(c => c.hasAttribute('selected')) ?? chips?.[0])?.focus()\n }\n\n updated() {\n const plan = this.revision && this.form ? fastenPlanOf(this.revision, this.partId, this.form) : undefined\n const candidate = plan?.action ? { action: plan.action, ...(plan.face ? { face: plan.face } : {}) } : null\n const said = JSON.stringify(candidate)\n if (said === this.told) return\n this.told = said\n this.dispatchEvent(new CustomEvent('preview-command', { detail: candidate, bubbles: true, composed: true }))\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n /* Closed: what it showed goes with it. */\n if (this.told && this.told !== 'null')\n this.dispatchEvent(new CustomEvent('preview-command', { detail: null, bubbles: true, composed: true }))\n this.told = ''\n this.hover(null)\n }\n\n render() {\n const revision = this.revision\n const f = this.form\n if (!revision || !f) return nothing\n const asset = revision.asset\n const held = !!heldBy(asset, this.partId)\n const plan = fastenPlanOf(revision, this.partId, f)\n const planeWord = i18next.t('figure.label.resize-place-' + (asset.placement ?? 'floor'))\n const modes: FastenMode[] = f.toPlane\n ? mountingPlaneOf(asset).facings\n : ['meet', 'flush', ...(turnsInPlace(asset, this.partId) ? (['centre'] as FastenMode[]) : [])]\n const detail = fastenDetailWordsOf(f, (key, params) => i18next.t(key, params))\n const drawing = (show: 'face' | 'how') =>\n html`<figure-fasten-drawing\n show=${show}\n .target=${f.toPlane ? '' : f.target}\n .planeWord=${planeWord}\n .faces=${plan.theirFaces}\n .face=${plan.targetFace}\n .modes=${modes}\n .mode=${plan.mode}\n .view=${plan.view}\n .align=${f.align}\n .alignMm=${f.alignMm}\n .gap=${f.gap}\n .partName=${this.partId}\n .surfaceForm=${f.toPlane || !f.target ? '' : (surfaceOf(asset, f.target)?.form ?? '')}\n .surface=${plan.surface}\n ?locked=${this.locked}\n @fasten-change=${(e: CustomEvent<FastenChange>) => {\n this.aimNote = ''\n this.form = fastenChanged(revision, this.partId, this.form!, e.detail)\n }}\n ></figure-fasten-drawing>`\n return html`\n ${\n plan.aim || plan.surface\n ? html`<p fasten-sentence role=\"status\">\n ${fastenSentenceOf(f, plan, planeWord, (key, params) => i18next.t(key, params))}\n </p>`\n : html`<p hint fasten-sentence>${i18next.t('figure.text.fasten-target-first')}</p>`\n }\n <div question=\"what\">\n <h4 id=\"what\">${i18next.t('figure.label.fasten-what')}</h4>\n ${this.renderTargets(revision, f, planeWord)}\n </div>\n ${\n plan.aim || plan.surface\n ? html`<div question=\"face\">\n <h4>\n ${\n /* The face asked is the target's, named: the part meets it by its real shape, by no face of its own. */ f.toPlane\n ? i18next.t('figure.label.fasten-face-on-plane', { plane: planeWord })\n : /* A sphere has no face to choose: where on its surface. */ plan.theirFaces.length\n ? i18next.t('figure.label.fasten-face-on-part', { part: f.target })\n : i18next.t('figure.label.fasten-face-on-surface', { part: f.target })\n }\n </h4>\n ${drawing('face')}\n </div>\n ${\n modes.length > 1\n ? html`<div question=\"how\">\n <h4>${i18next.t('figure.label.fasten-how')}</h4>\n ${drawing('how')}\n </div>`\n : nothing\n }\n <div question=\"detail\">\n <details fasten-detail>\n <summary>\n ${i18next.t('figure.label.fasten-detail')}${detail.length ? html` · <span fasten-summary>${detail.join(' · ')}</span>` : nothing}\n </summary>\n ${plan.alignRows.length ? this.renderAlignment(plan.alignRows) : nothing}\n <div form>\n <span>${i18next.t('figure.label.gap')}</span>\n <input\n gap\n type=\"number\"\n step=\"any\"\n .value=${f.gapKept !== undefined ? '' : String(f.gap)}\n placeholder=${f.gapKept !== undefined ? i18next.t('figure.label.follows-expression') : ''}\n @change=${(e: Event) => this.set({ gap: Number((e.target as HTMLInputElement).value) || 0, gapKept: undefined })}\n />\n </div>\n </details>\n </div>\n ${/* The one it has, tried unchanged: that it stays where it is goes without saying. */ JSON.stringify(plan.action ?? null) === this.opened ? nothing : this.renderPreviewWords()}`\n : nothing\n }\n ${this.aimNote ? html`<p hint aim-note role=\"status\">${this.aimNote}</p>` : nothing}\n ${this.error ? html`<p error role=\"alert\">${this.error}</p>` : nothing}\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" cancel @click=${this.cancel}>${i18next.t('figure.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" apply ?disabled=${this.locked || !plan.action} @click=${this.apply}>\n ${i18next.t(held ? 'figure.button.apply' : 'figure.button.fasten')}\n </md-filled-button>\n </ox-popup-actions>\n `\n }\n\n /**\n * What to fasten to: the plane and the other parts, as the standard choice chips. The arrows move among them and\n * the canvas lights the part under the focus or the pointer; a part hanging from this one is not offered, and why is\n * said under them.\n */\n private renderTargets(revision: FigureRevision, f: FastenForm, planeWord: string) {\n const chosen = f.toPlane ? PLANE : f.target\n const targets = fastenTargetsOf(revision, this.partId)\n const chipOf = (e: Event) =>\n (e.composedPath().find(n => (n as Element).localName === 'md-filter-chip') as Element | undefined)?.getAttribute(\n 'data-value'\n ) ?? null\n return html`<ox-input-select-buttons\n targets\n aria-labelledby=\"what\"\n .options=${[{ value: PLANE, display: planeWord }, ...targets.filter(t => !t.loops).map(t => ({ value: t.part, display: t.part }))]}\n .value=${chosen || undefined}\n ?disabled=${this.locked}\n @change=${(e: CustomEvent) => {\n /* A chip pressed again lets go of it; what to fasten to is always one thing once chosen. */\n if (e.detail) this.aim(e.detail)\n else (e.target as HTMLElement & { value?: string }).value = chosen || undefined\n }}\n @pointerover=${(e: Event) => this.hover(chipOf(e))}\n @pointerleave=${() => this.hover(null)}\n @focusin=${(e: Event) => this.hover(chipOf(e))}\n @keyup=${(e: KeyboardEvent) => {\n /* The arrows move the focus among the chips inside the list, which tells nothing outside it: read where it is. */\n const at = (e.currentTarget as Element).shadowRoot?.activeElement\n if (at?.localName === 'md-filter-chip') this.hover(at.getAttribute('data-value'))\n }}\n ></ox-input-select-buttons>\n ${this.renderLoops(targets.filter(t => t.loops).map(t => t.part))}`\n }\n\n /**\n * The parts that hang from this one, in one line: a line each made a list longer than the chips (2026-10-18, :3300,\n * the robot arm's forearm and the six parts it carries).\n */\n private renderLoops(parts: string[]) {\n if (!parts.length) return nothing\n return html`<p hint loops targets=${parts.join(',')}>\n ${i18next.t('figure.text.target-would-loop', { part: parts.join(', '), mine: this.partId })}\n </p>`\n }\n\n private aim(part: string) {\n if (this.locked || !this.revision || !this.form) return\n this.aimNote = ''\n const chosen = this.form.toPlane ? PLANE : this.form.target\n if (part === chosen) return\n this.form = aimFasten(this.revision, this.partId, this.form, part === PLANE ? { plane: true } : { part })\n }\n\n /**\n * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed\n * -- the kernel's reading of the press (`figureFastenTargetAt`), the point and normal brought into that part's own\n * frame by the pose it is drawn at. The part itself, or one hanging from it, is not aimed at; and a press on a curve\n * there is no fastening to aims at the part alone. Each is said.\n */\n aimAt(at: { id: string; point?: number[]; normal?: number[] }) {\n if (this.locked || !this.revision || !this.form) return\n const aimed = aimFastenAt(this.revision, this.partId, this.form, at)\n this.aimNote = aimed.note ? i18next.t(`figure.text.${aimed.note}`, { part: aimed.part, mine: this.partId }) : ''\n if (aimed.form) this.form = aimed.form\n }\n\n /** The part under the pointer or the focus in the list, for the canvas to light; the plane lights nothing. */\n private hover(part: string | null) {\n const lit = part && part !== PLANE ? part : null\n if (lit === this.hovered) return\n this.hovered = lit\n const face =\n lit && this.revision && this.form\n ? fastenPlanOf(this.revision, this.partId, aimFasten(this.revision, this.partId, this.form, { part: lit }))\n .targetFace\n : undefined\n this.dispatchEvent(\n new CustomEvent('fasten-hover', { detail: lit ? { part: lit, face } : null, bubbles: true, composed: true })\n )\n }\n\n private set(change: Partial<FastenForm>) {\n this.form = { ...this.form!, ...change }\n }\n\n /**\n * Where on the target face the part sits, on the axes the drawing cannot set: centred, level with the target's edge on\n * either side, a distance off centre, a share of the figure's size, or the position field it follows.\n */\n private renderAlignment(axes: { axis: Axis; edges: boolean }[]) {\n const f = this.form!\n const set = (axis: Axis, how: Alignment) => this.set({ align: { ...f.align, [axis]: how } })\n const setMm = (axis: Axis, mm: number) => this.set({ alignMm: { ...f.alignMm, [axis]: mm } })\n return html`<div form>\n ${axes.map(({ axis, edges }) => {\n const how =\n f.align[axis] === 'min' || f.align[axis] === 'max'\n ? edges\n ? f.align[axis]!\n : 'centre'\n : (f.align[axis] ?? 'centre')\n return html`<span>${i18next.t('figure.label.align-' + axis)}</span>\n <select @change=${(e: Event) => set(axis, (e.target as HTMLSelectElement).value as Alignment)}>\n <option value=\"centre\" ?selected=${how === 'centre'}>${i18next.t('figure.label.align-centre')}</option>\n ${\n edges\n ? html`<option value=\"min\" ?selected=${how === 'min'}>\n ${i18next.t(`figure.label.align-${axis}-min`)}\n </option>\n <option value=\"max\" ?selected=${how === 'max'}>\n ${i18next.t(`figure.label.align-${axis}-max`)}\n </option>`\n : nothing\n }\n ${\n f.alignInput?.[axis]\n ? html`<option value=\"input\" ?selected=${how === 'input'}>\n ${i18next.t('figure.label.align-input', { field: fieldWordsOf(f.alignInput[axis]!, key => i18next.t(key)) })}\n </option>`\n : nothing\n }\n <option value=\"mm\" ?selected=${how === 'mm'}>${i18next.t('figure.label.align-mm')}</option>\n ${\n this.revision && hasInstanceSize(this.revision.asset, axis)\n ? html`<option value=\"share\" ?selected=${how === 'share'}>\n ${i18next.t('figure.label.align-share')}\n </option>`\n : nothing\n }\n </select>\n ${\n how === 'mm' || how === 'share'\n ? html`<span></span\n ><input\n type=\"number\"\n step=\"any\"\n aria-label=${i18next.t('figure.label.align-mm')}\n .value=${String(f.alignMm[axis] ?? 0)}\n @change=${(e: Event) => setMm(axis, Number((e.target as HTMLInputElement).value) || 0)}\n />`\n : nothing\n }`\n })}\n </div>`\n }\n\n private renderPreviewWords() {\n if (this.previewWords.length === 1) return html`<p preview-words role=\"status\">${this.previewWords[0]}</p>`\n return this.previewWords.length\n ? html`<ul preview-words role=\"status\">\n ${this.previewWords.map(line => html`<li>${line}</li>`)}\n </ul>`\n : nothing\n }\n\n /** Enter applies what is chosen, Esc closes with nothing written; a key the window does not take goes on. */\n connectedCallback() {\n super.connectedCallback()\n this.setAttribute('role', 'dialog')\n this.setAttribute('aria-label', i18next.t('figure.label.fastening'))\n this.addEventListener('keydown', this.onKey)\n /* The popup's fitting width is the overlay's own setting; the window asks it for room for the face and the way side by side. */\n this.closest<HTMLElement>('ox-floating-overlay')?.style.setProperty('--overlay-center-fit-width', '640px')\n }\n\n private onKey = async (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n e.preventDefault()\n this.cancel()\n return\n }\n if (e.key !== 'Enter' || e.isComposing) return\n const path = e.composedPath() as Element[]\n const target = path[0] as HTMLElement\n /* On a chip of the list Enter applies, as it does anywhere in the window; a chip is chosen by Space or a press. */\n const onChip = path.some(n => n.localName === 'ox-input-select-buttons')\n /* A button, a fold or a list of options does what Enter does to it. */\n if (\n !onChip &&\n (target.localName === 'button' ||\n target.localName === 'summary' ||\n target.localName === 'select' ||\n /^md-.*button$/.test(target.localName))\n )\n return\n e.preventDefault()\n e.stopPropagation()\n /* A number typed and Enter: the number first, as leaving the field would take it. */\n if (target.localName === 'input') target.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n await this.updateComplete\n this.apply()\n }\n\n private apply = () => {\n const plan = this.revision && this.form ? fastenPlanOf(this.revision, this.partId, this.form) : undefined\n if (this.locked || !plan?.action) return\n this.dispatchEvent(\n new CustomEvent('fasten-apply', { detail: { action: plan.action }, bubbles: true, composed: true })\n )\n }\n\n private cancel = () => {\n this.dispatchEvent(new CustomEvent('fasten-cancel', { bubbles: true, composed: true }))\n }\n}\n"]}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { LitElement, nothing } from 'lit';
|
|
2
|
+
import type { FigureSurfacePlace } from '@hatiolab/figure-model';
|
|
2
3
|
import { type FaceView, type FastenMode } from './fasten-geometry.js';
|
|
3
4
|
import type { Alignment } from './links.js';
|
|
4
5
|
type Axis = 'x' | 'y' | 'z';
|
|
5
6
|
/** A change the drawing asks of the fastening form. */
|
|
6
7
|
export type FastenChange = {
|
|
7
8
|
targetFace: string;
|
|
9
|
+
} | {
|
|
10
|
+
onSurface: true;
|
|
11
|
+
} | {
|
|
12
|
+
surface: FigureSurfacePlace;
|
|
8
13
|
} | {
|
|
9
14
|
mode: FastenMode;
|
|
10
15
|
} | {
|
|
@@ -29,7 +34,7 @@ declare const FigureFastenDrawing_base: (new (...args: any[]) => LitElement) & t
|
|
|
29
34
|
* questions: the face (`show="face"`: the box and the face seen from above, side by side) and the way (`show="how"`).
|
|
30
35
|
*/
|
|
31
36
|
export declare class FigureFastenDrawing extends FigureFastenDrawing_base {
|
|
32
|
-
static styles: import("lit").CSSResult;
|
|
37
|
+
static styles: import("lit").CSSResult[];
|
|
33
38
|
/** The target's name, or empty for the plane the figure stands by. */
|
|
34
39
|
target: string;
|
|
35
40
|
/** The plane's name by the figure's placement: 바닥 · 천장 · 벽 · 중심. */
|
|
@@ -49,6 +54,16 @@ export declare class FigureFastenDrawing extends FigureFastenDrawing_base {
|
|
|
49
54
|
said: boolean;
|
|
50
55
|
/** Which of its questions it draws: the face, or the way. */
|
|
51
56
|
show: 'face' | 'how';
|
|
57
|
+
/** The curved surface the target offers to be fastened to at a point (ADR-0140 3.9), if any. */
|
|
58
|
+
surfaceForm: 'around' | 'toward' | '';
|
|
59
|
+
/** Fastened to a point of that surface: which, about which axis, and where; undefined while on a face. */
|
|
60
|
+
surface?: {
|
|
61
|
+
form: 'around' | 'toward';
|
|
62
|
+
axis: Axis;
|
|
63
|
+
place: FigureSurfacePlace;
|
|
64
|
+
};
|
|
65
|
+
/** The angles while one is dragged round the surface, told to the form when let go. */
|
|
66
|
+
private turning?;
|
|
52
67
|
/** Where the footprint is while dragging, and what it is caught by; undefined when nothing is dragged. */
|
|
53
68
|
private dragged?;
|
|
54
69
|
private typing?;
|
|
@@ -73,5 +88,22 @@ export declare class FigureFastenDrawing extends FigureFastenDrawing_base {
|
|
|
73
88
|
private drop;
|
|
74
89
|
/** Arrows move the part a millimetre, ten with Shift; the centre and edges still catch it. */
|
|
75
90
|
private keys;
|
|
91
|
+
/**
|
|
92
|
+
* Where on a curved surface (ADR-0140 3.9). A cylinder's side is seen from its end: its section a circle, the point
|
|
93
|
+
* on its rim at the angle `around`, dragged round it -- caught at every 45°, where the faces it had are named -- and
|
|
94
|
+
* along its length chosen below it. A sphere is seen from above and from the side: its point dragged round the
|
|
95
|
+
* first for the direction across its axis, along the second for how high. Nothing is told the form until let go.
|
|
96
|
+
*/
|
|
97
|
+
private renderSurfaceWhere;
|
|
98
|
+
/** Where along a cylinder's side: centred, level with an end, or a distance from the middle -- its alignment words. */
|
|
99
|
+
private renderAlong;
|
|
100
|
+
/** A pointer's place in the drawing's own units. */
|
|
101
|
+
private pointIn;
|
|
102
|
+
/** Let go: the angles dragged become the place, told to the form once. */
|
|
103
|
+
private letGo;
|
|
104
|
+
/** The place the angles come to: the kernel's (`figureSurfacePlaceOf`), along a side kept. */
|
|
105
|
+
private placeOf;
|
|
106
|
+
/** Arrows turn it a degree, fifteen with Shift: round the side, or round and up and down a sphere. */
|
|
107
|
+
private turnKeys;
|
|
76
108
|
}
|
|
77
109
|
export {};
|
|
@@ -2,7 +2,10 @@ import { __decorate, __metadata } from "tslib";
|
|
|
2
2
|
import { css, html, LitElement, nothing, svg } from 'lit';
|
|
3
3
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
4
4
|
import { i18next, localize } from '@operato/i18n';
|
|
5
|
+
import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js';
|
|
6
|
+
import { figureAroundNormalOf, figureAroundOf, figureCaughtAngleOf, figureSurfaceAnglesOf, figureSurfacePlaceOf } from '@hatiolab/figure-model';
|
|
5
7
|
import { alignmentAt, fastenLabelsOf, offsetOf, overhangOf, screenOf } from './fasten-geometry.js';
|
|
8
|
+
const AXES = ['x', 'y', 'z'];
|
|
6
9
|
const SEEN = [
|
|
7
10
|
['top', 'M60 30 L100 10 L200 10 L160 30 Z'],
|
|
8
11
|
['front', 'M60 30 L160 30 L160 100 L60 100 Z'],
|
|
@@ -53,9 +56,12 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
53
56
|
this.said = false;
|
|
54
57
|
/** Which of its questions it draws: the face, or the way. */
|
|
55
58
|
this.show = 'face';
|
|
59
|
+
/** The curved surface the target offers to be fastened to at a point (ADR-0140 3.9), if any. */
|
|
60
|
+
this.surfaceForm = '';
|
|
56
61
|
this.scale = 1;
|
|
57
62
|
}
|
|
58
|
-
|
|
63
|
+
/* The panel's own field rows (where along a cylinder's side), as the window's other rows are. */
|
|
64
|
+
static { this.styles = [SidePanelStyles, css `
|
|
59
65
|
:host {
|
|
60
66
|
display: grid;
|
|
61
67
|
gap: 8px;
|
|
@@ -96,6 +102,29 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
96
102
|
div[modes] button:hover:not([on]):not(:disabled) {
|
|
97
103
|
background: var(--md-sys-color-surface-container);
|
|
98
104
|
}
|
|
105
|
+
/* Faces beyond the box's six and a curved surface: tags as the hidden faces are drawn beside the box -- one look for every face. */
|
|
106
|
+
div[face-tags] {
|
|
107
|
+
display: flex;
|
|
108
|
+
flex-wrap: wrap;
|
|
109
|
+
justify-content: center;
|
|
110
|
+
gap: 6px;
|
|
111
|
+
}
|
|
112
|
+
button[face-tag] {
|
|
113
|
+
height: 20px;
|
|
114
|
+
padding: 0 10px;
|
|
115
|
+
font: inherit;
|
|
116
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
117
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
118
|
+
background: transparent;
|
|
119
|
+
border: 1px dashed var(--md-sys-color-outline);
|
|
120
|
+
border-radius: 10px;
|
|
121
|
+
cursor: pointer;
|
|
122
|
+
}
|
|
123
|
+
button[face-tag][on] {
|
|
124
|
+
color: var(--md-sys-color-on-primary-container);
|
|
125
|
+
background: var(--md-sys-color-primary-container);
|
|
126
|
+
border: 1px solid var(--md-sys-color-primary);
|
|
127
|
+
}
|
|
99
128
|
div[modes] button[on] {
|
|
100
129
|
background: var(--md-sys-color-primary-container);
|
|
101
130
|
color: var(--md-sys-color-on-primary-container);
|
|
@@ -111,8 +140,12 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
111
140
|
display: grid;
|
|
112
141
|
gap: 8px;
|
|
113
142
|
}
|
|
143
|
+
/* The place is drawn at its own size, never blown up past it: its words stay the window's size. */
|
|
114
144
|
div[where] {
|
|
115
145
|
position: relative;
|
|
146
|
+
width: 100%;
|
|
147
|
+
max-width: 360px;
|
|
148
|
+
justify-self: center;
|
|
116
149
|
}
|
|
117
150
|
div[where] input {
|
|
118
151
|
position: absolute;
|
|
@@ -125,7 +158,7 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
125
158
|
small[off] {
|
|
126
159
|
color: var(--md-sys-color-error);
|
|
127
160
|
}
|
|
128
|
-
|
|
161
|
+
`]; }
|
|
129
162
|
change(detail) {
|
|
130
163
|
this.dispatchEvent(new CustomEvent('fasten-change', { detail, bubbles: true, composed: true }));
|
|
131
164
|
}
|
|
@@ -135,6 +168,9 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
135
168
|
render() {
|
|
136
169
|
if (this.show === 'how')
|
|
137
170
|
return this.renderModes();
|
|
171
|
+
/* A part with no face (a sphere) has only its surface: its tag above, the place across the whole width. */
|
|
172
|
+
if (this.target && !this.faces.length)
|
|
173
|
+
return html `${this.renderTarget()}<div>${this.renderWhere()}</div>`;
|
|
138
174
|
return html `<div face-row>${this.target ? html `<div>${this.renderTarget()}</div>` : nothing}<div>${this.renderWhere()}</div></div>`;
|
|
139
175
|
}
|
|
140
176
|
/** The target box, its faces pressed; or the plane. */
|
|
@@ -145,19 +181,19 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
145
181
|
const has = (f) => this.faces.includes(f);
|
|
146
182
|
/* A press is a whole change, as a drag let go is: the form applies a fastening the part already has. */
|
|
147
183
|
const pick = (f) => () => {
|
|
148
|
-
if (this.locked || !has(f) || f === this.face)
|
|
184
|
+
if (this.locked || !has(f) || (!this.surface && f === this.face))
|
|
149
185
|
return;
|
|
150
186
|
this.change({ targetFace: f });
|
|
151
187
|
this.released();
|
|
152
188
|
};
|
|
153
189
|
const seen = SEEN.map(([f, d]) => {
|
|
154
|
-
const on = this.face === f;
|
|
190
|
+
const on = !this.surface && this.face === f;
|
|
155
191
|
return svg `<path face=${f} d=${d} @click=${pick(f)}
|
|
156
192
|
style=${`cursor:${has(f) ? 'pointer' : 'default'};fill:${on ? 'var(--md-sys-color-primary-container)' : 'var(--md-sys-color-surface-container)'};fill-opacity:${has(f) ? 1 : 0.4};stroke:${on ? 'var(--md-sys-color-primary)' : 'var(--md-sys-color-outline)'};stroke-width:${on ? 2 : 1}`}>
|
|
157
193
|
<title>${i18next.t('figure.label.face-' + f)}</title></path>`;
|
|
158
194
|
});
|
|
159
195
|
const hidden = HIDDEN.map(([f, x, y]) => {
|
|
160
|
-
const on = this.face === f;
|
|
196
|
+
const on = !this.surface && this.face === f;
|
|
161
197
|
return svg `<g face=${f} @click=${pick(f)} style=${`cursor:${has(f) ? 'pointer' : 'default'};opacity:${has(f) ? 1 : 0.35}`}>
|
|
162
198
|
<rect x=${x - 26} y=${y - 10} width="52" height="20" rx="10"
|
|
163
199
|
style=${`fill:${on ? 'var(--md-sys-color-primary-container)' : 'transparent'};stroke:${on ? 'var(--md-sys-color-primary)' : 'var(--md-sys-color-outline)'};stroke-dasharray:${on ? '' : '3 2'}`} />
|
|
@@ -166,14 +202,26 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
166
202
|
});
|
|
167
203
|
/* A shape's faces beyond its six outer ones -- a door frame's opening -- are tags of their own under the box. */
|
|
168
204
|
const others = this.faces.filter(f => !SEEN.some(([s]) => s === f) && !HIDDEN.some(([h]) => h === f));
|
|
169
|
-
|
|
205
|
+
/* A sphere has no face: no box of faces it has not, only its surface. */
|
|
206
|
+
return html `${this.faces.length
|
|
207
|
+
? svg `<svg viewBox="-20 0 ${PANEL_W} 126" role="img" aria-label=${this.target}>
|
|
170
208
|
${seen}
|
|
171
209
|
<text x="110" y="70" text-anchor="middle" font-size="12" pointer-events="none" style="fill:var(--md-sys-color-on-surface)">${this.target}</text>
|
|
172
210
|
${hidden}
|
|
173
|
-
</svg>`
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
211
|
+
</svg>`
|
|
212
|
+
: nothing}
|
|
213
|
+
${others.length || this.surfaceForm
|
|
214
|
+
? html `<div face-tags>
|
|
215
|
+
${others.map(f => html `<button face-tag ?on=${!this.surface && f === this.face} ?disabled=${this.locked} @click=${pick(f)}>${i18next.t('figure.label.face-' + f, { defaultValue: f })}</button>`)}
|
|
216
|
+
${this.surfaceForm
|
|
217
|
+
? html `<button face-tag surface ?on=${!!this.surface} ?disabled=${this.locked}
|
|
218
|
+
@click=${() => {
|
|
219
|
+
if (this.locked || this.surface)
|
|
220
|
+
return;
|
|
221
|
+
this.change({ onSurface: true });
|
|
222
|
+
this.released();
|
|
223
|
+
}}>${i18next.t('figure.label.surface-' + this.surfaceForm)}</button>`
|
|
224
|
+
: nothing}
|
|
177
225
|
</div>`
|
|
178
226
|
: nothing}`;
|
|
179
227
|
}
|
|
@@ -253,6 +301,8 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
253
301
|
return out;
|
|
254
302
|
}
|
|
255
303
|
renderWhere() {
|
|
304
|
+
if (this.surface)
|
|
305
|
+
return this.renderSurfaceWhere(this.surface);
|
|
256
306
|
const view = this.view;
|
|
257
307
|
if (!view)
|
|
258
308
|
return nothing;
|
|
@@ -269,6 +319,8 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
269
319
|
const pw = view.part[h] * k, ph = view.part[v] * k;
|
|
270
320
|
const px = cx + sign[h] * at[h] * k - pw / 2, py = cy + sign[v] * at[v] * k - ph / 2;
|
|
271
321
|
const faceSized = view.face[h] !== undefined && view.face[v] !== undefined;
|
|
322
|
+
/* An end disc is drawn as the disc it is: its overhang is measured on it (ADR-0140 3.9). */
|
|
323
|
+
const disc = !!view.measure.disc;
|
|
272
324
|
const fx = cx - fw / 2, fy = cy - fh / 2;
|
|
273
325
|
const ix = Math.max(fx, px), iy = Math.max(fy, py);
|
|
274
326
|
const iw = Math.min(fx + fw, px + pw) - ix, ih = Math.min(fy + fh, py + ph) - iy;
|
|
@@ -307,7 +359,7 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
307
359
|
@pointermove=${(ev) => this.drag(ev, view, cx, cy)}
|
|
308
360
|
@pointerup=${() => this.drop()} @pointercancel=${() => this.drop()}>
|
|
309
361
|
${faceSized
|
|
310
|
-
? svg `<rect x=${fx} y=${fy} width=${fw} height=${fh} rx
|
|
362
|
+
? svg `<rect x=${fx} y=${fy} width=${fw} height=${fh} rx=${disc ? fw / 2 : 4} ry=${disc ? fh / 2 : 4} style="fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:2" />`
|
|
311
363
|
: svg `<rect x="1" y="1" width=${W - 2} height=${H - 2} rx="8" style="fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:2" />`}
|
|
312
364
|
<text face-name x=${labels.face.x} y=${labels.face.y} font-size="11" pointer-events="none" style="fill:var(--md-sys-color-primary)">${faceName}${sizeWords}</text>
|
|
313
365
|
${guide(h)}${guide(v)}
|
|
@@ -413,6 +465,166 @@ let FigureFastenDrawing = class FigureFastenDrawing extends localize(i18next)(Li
|
|
|
413
465
|
});
|
|
414
466
|
this.released();
|
|
415
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* Where on a curved surface (ADR-0140 3.9). A cylinder's side is seen from its end: its section a circle, the point
|
|
470
|
+
* on its rim at the angle `around`, dragged round it -- caught at every 45°, where the faces it had are named -- and
|
|
471
|
+
* along its length chosen below it. A sphere is seen from above and from the side: its point dragged round the
|
|
472
|
+
* first for the direction across its axis, along the second for how high. Nothing is told the form until let go.
|
|
473
|
+
*/
|
|
474
|
+
renderSurfaceWhere(surface) {
|
|
475
|
+
const R = 56;
|
|
476
|
+
const axis = surface.axis;
|
|
477
|
+
const across = ['x', 'y', 'z'].filter(a => a !== axis);
|
|
478
|
+
const { h, v, sign } = screenOf(across);
|
|
479
|
+
const deg = (r) => (r * 180) / Math.PI;
|
|
480
|
+
const rad = (d) => (d * Math.PI) / 180;
|
|
481
|
+
/* A direction across the axis on the circle drawn at (cx, cy): its point there, and the way back from a pointer. */
|
|
482
|
+
const onCircle = (n, cx, cy, r = R) => ({ x: cx + sign[h] * n[AXES.indexOf(h)] * r, y: cy + sign[v] * n[AXES.indexOf(v)] * r });
|
|
483
|
+
const angleAt = (p, cx, cy) => {
|
|
484
|
+
const d = [0, 0, 0];
|
|
485
|
+
d[AXES.indexOf(h)] = sign[h] * (p.x - cx);
|
|
486
|
+
d[AXES.indexOf(v)] = sign[v] * (p.y - cy);
|
|
487
|
+
return figureAroundOf(axis, d);
|
|
488
|
+
};
|
|
489
|
+
const caught = (a) => figureCaughtAngleOf(a) % 360;
|
|
490
|
+
/* The faces the four quarters were named by, round the circle: where a part fastened to one of them now stands. */
|
|
491
|
+
const FACE_AT = { x: ['left', 'right'], y: ['bottom', 'top'], z: ['back', 'front'] };
|
|
492
|
+
const ticks = (cx, cy) => [0, 90, 180, 270].map(t => {
|
|
493
|
+
const n = figureAroundNormalOf(axis, t);
|
|
494
|
+
const k = n.findIndex(c => Math.abs(c) > 0.5);
|
|
495
|
+
const word = i18next.t('figure.label.face-' + FACE_AT[AXES[k]][n[k] > 0 ? 1 : 0]);
|
|
496
|
+
const p = onCircle(n, cx, cy, R + 16);
|
|
497
|
+
return svg `<text x=${p.x} y=${p.y + 4} text-anchor="middle" font-size="10" pointer-events="none" style="fill:var(--md-sys-color-on-surface-variant)">${word}</text>`;
|
|
498
|
+
});
|
|
499
|
+
const marker = (p, cx, cy, label) => svg `
|
|
500
|
+
<line x1=${cx} y1=${cy} x2=${p.x} y2=${p.y} style="stroke:var(--md-sys-color-primary);stroke-dasharray:3 2" />
|
|
501
|
+
<circle marker cx=${p.x} cy=${p.y} r="8" style=${`fill:var(--md-sys-color-tertiary-container);stroke:var(--md-sys-color-on-surface);cursor:${this.locked ? 'default' : 'grab'}`} />
|
|
502
|
+
<text x=${cx} y=${Math.hypot(p.x - cx, p.y - cy) < 16 ? cy - 14 : cy + 4} text-anchor="middle" font-size="11" pointer-events="none" style="fill:var(--md-sys-color-primary)">${label}</text>`;
|
|
503
|
+
const drag = (on) => ({
|
|
504
|
+
down: (ev) => {
|
|
505
|
+
if (this.locked)
|
|
506
|
+
return;
|
|
507
|
+
ev.currentTarget.setPointerCapture(ev.pointerId);
|
|
508
|
+
on(this.pointIn(ev));
|
|
509
|
+
},
|
|
510
|
+
move: (ev) => {
|
|
511
|
+
if (!this.turning || !ev.currentTarget.hasPointerCapture?.(ev.pointerId))
|
|
512
|
+
return;
|
|
513
|
+
on(this.pointIn(ev));
|
|
514
|
+
},
|
|
515
|
+
up: () => this.letGo(surface)
|
|
516
|
+
});
|
|
517
|
+
if (surface.form === 'around') {
|
|
518
|
+
const place = surface.place;
|
|
519
|
+
const around = this.turning?.around ?? place.around;
|
|
520
|
+
/* The section in the middle under its name, the ticks clear of both. */
|
|
521
|
+
const cx = WHERE_W / 2, cy = 110;
|
|
522
|
+
const d = drag(p => (this.turning = { around: caught(angleAt(p, cx, cy)) }));
|
|
523
|
+
return html `<div where surface tabindex="0" @keydown=${(ev) => this.turnKeys(ev, surface)}>
|
|
524
|
+
${svg `<svg viewBox="0 0 ${WHERE_W} ${WHERE_H}" role="img" aria-label=${i18next.t('figure.label.surface-seen-end', { part: this.target })}
|
|
525
|
+
@pointerdown=${d.down} @pointermove=${d.move} @pointerup=${d.up} @pointercancel=${d.up}>
|
|
526
|
+
<text x=${WHERE_W / 2} y="14" text-anchor="middle" font-size="11" pointer-events="none" style="fill:var(--md-sys-color-primary)">${i18next.t('figure.label.surface-seen-end', { part: this.target })}</text>
|
|
527
|
+
<circle cx=${cx} cy=${cy} r=${R} style="fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:2" />
|
|
528
|
+
${ticks(cx, cy)}
|
|
529
|
+
${marker(onCircle(figureAroundNormalOf(axis, around), cx, cy), cx, cy, `${Math.round(around)}°`)}
|
|
530
|
+
</svg>`}
|
|
531
|
+
</div>
|
|
532
|
+
${this.renderAlong(surface.axis, place.along)}`;
|
|
533
|
+
}
|
|
534
|
+
/* A sphere: its direction across its axis (the azimuth, by the same rule as a cylinder's around) and how high. */
|
|
535
|
+
const now = figureSurfaceAnglesOf(surface, surface.place);
|
|
536
|
+
const azimuth = this.turning?.azimuth ?? now.azimuth;
|
|
537
|
+
const elevation = this.turning?.elevation ?? now.elevation;
|
|
538
|
+
const ax = 110, ay = 110, sx = 250, sy = 110;
|
|
539
|
+
const aboveAt = onCircle(figureAroundNormalOf(axis, azimuth), ax, ay, R * Math.cos(rad(elevation)) || 0);
|
|
540
|
+
const sideAt = { x: sx + R * Math.cos(rad(elevation)), y: sy - R * Math.sin(rad(elevation)) };
|
|
541
|
+
const d = drag(p => {
|
|
542
|
+
const above = Math.hypot(p.x - ax, p.y - ay) <= R + 16 && p.x < (ax + sx) / 2;
|
|
543
|
+
this.turning = above
|
|
544
|
+
? { azimuth: caught(angleAt(p, ax, ay)), elevation }
|
|
545
|
+
: { azimuth, elevation: Math.max(-90, Math.min(90, figureCaughtAngleOf(deg(Math.atan2(sy - p.y, Math.max(0, p.x - sx)))))) };
|
|
546
|
+
});
|
|
547
|
+
return html `<div where surface tabindex="0" @keydown=${(ev) => this.turnKeys(ev, surface)}>
|
|
548
|
+
${svg `<svg viewBox="0 0 ${WHERE_W} ${WHERE_H}" role="img" aria-label=${i18next.t('figure.label.surface-toward')}
|
|
549
|
+
@pointerdown=${d.down} @pointermove=${d.move} @pointerup=${d.up} @pointercancel=${d.up}>
|
|
550
|
+
<text x=${ax} y="14" text-anchor="middle" font-size="11" pointer-events="none" style="fill:var(--md-sys-color-primary)">${i18next.t('figure.label.surface-seen-above')}</text>
|
|
551
|
+
<circle cx=${ax} cy=${ay} r=${R} style="fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:2" />
|
|
552
|
+
${ticks(ax, ay)}
|
|
553
|
+
${marker(aboveAt, ax, ay, `${Math.round(azimuth)}°`)}
|
|
554
|
+
<text x=${sx + R / 2} y="14" text-anchor="middle" font-size="11" pointer-events="none" style="fill:var(--md-sys-color-primary)">${i18next.t('figure.label.surface-seen-side')}</text>
|
|
555
|
+
<path d=${`M ${sx} ${sy - R} A ${R} ${R} 0 0 1 ${sx} ${sy + R}`} style="fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:2" />
|
|
556
|
+
<line x1=${sx} y1=${sy - R} x2=${sx} y2=${sy + R} style="stroke:var(--md-sys-color-primary)" />
|
|
557
|
+
${marker(sideAt, sx, sy, `${Math.round(elevation)}°`)}
|
|
558
|
+
</svg>`}
|
|
559
|
+
</div>`;
|
|
560
|
+
}
|
|
561
|
+
/** Where along a cylinder's side: centred, level with an end, or a distance from the middle -- its alignment words. */
|
|
562
|
+
renderAlong(axis, along) {
|
|
563
|
+
const how = along === 'min' || along === 'max' ? along : along && typeof along === 'object' ? 'mm' : 'centre';
|
|
564
|
+
const mm = how === 'mm' ? Number(along.mm) || 0 : 0;
|
|
565
|
+
const place = this.surface.place;
|
|
566
|
+
const tell = (next) => {
|
|
567
|
+
this.change({ surface: { around: place.around, along: next } });
|
|
568
|
+
this.released();
|
|
569
|
+
};
|
|
570
|
+
return html `<div form along>
|
|
571
|
+
<span>${i18next.t('figure.label.align-' + axis)}</span>
|
|
572
|
+
<select ?disabled=${this.locked} @change=${(e) => {
|
|
573
|
+
const v = e.target.value;
|
|
574
|
+
tell(v === 'mm' ? { mm } : v);
|
|
575
|
+
}}>
|
|
576
|
+
<option value="centre" ?selected=${how === 'centre'}>${i18next.t('figure.label.align-centre')}</option>
|
|
577
|
+
<option value="min" ?selected=${how === 'min'}>${i18next.t(`figure.label.align-${axis}-min`)}</option>
|
|
578
|
+
<option value="max" ?selected=${how === 'max'}>${i18next.t(`figure.label.align-${axis}-max`)}</option>
|
|
579
|
+
<option value="mm" ?selected=${how === 'mm'}>${i18next.t('figure.label.align-mm')}</option>
|
|
580
|
+
</select>
|
|
581
|
+
${how === 'mm'
|
|
582
|
+
? html `<span></span><input type="number" step="any" aria-label=${i18next.t('figure.label.align-mm')} .value=${String(mm)}
|
|
583
|
+
?disabled=${this.locked} @change=${(e) => tell({ mm: Number(e.target.value) || 0 })} />`
|
|
584
|
+
: nothing}
|
|
585
|
+
</div>`;
|
|
586
|
+
}
|
|
587
|
+
/** A pointer's place in the drawing's own units. */
|
|
588
|
+
pointIn(ev) {
|
|
589
|
+
const svgEl = ev.currentTarget.closest('svg');
|
|
590
|
+
const pt = svgEl.createSVGPoint();
|
|
591
|
+
pt.x = ev.clientX;
|
|
592
|
+
pt.y = ev.clientY;
|
|
593
|
+
return pt.matrixTransform(svgEl.getScreenCTM().inverse());
|
|
594
|
+
}
|
|
595
|
+
/** Let go: the angles dragged become the place, told to the form once. */
|
|
596
|
+
letGo(surface) {
|
|
597
|
+
const t = this.turning;
|
|
598
|
+
if (!t)
|
|
599
|
+
return;
|
|
600
|
+
this.turning = undefined;
|
|
601
|
+
this.change({ surface: this.placeOf(surface, t) });
|
|
602
|
+
this.released();
|
|
603
|
+
}
|
|
604
|
+
/** The place the angles come to: the kernel's (`figureSurfacePlaceOf`), along a side kept. */
|
|
605
|
+
placeOf(surface, t) {
|
|
606
|
+
const now = figureSurfaceAnglesOf(surface, surface.place);
|
|
607
|
+
const angles = surface.form === 'around' ? { around: t.around ?? now.around } : { azimuth: t.azimuth ?? now.azimuth, elevation: t.elevation ?? now.elevation };
|
|
608
|
+
return figureSurfacePlaceOf(surface, surface.place, angles);
|
|
609
|
+
}
|
|
610
|
+
/** Arrows turn it a degree, fifteen with Shift: round the side, or round and up and down a sphere. */
|
|
611
|
+
turnKeys(ev, surface) {
|
|
612
|
+
const step = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, 1], ArrowDown: [0, -1] }[ev.key];
|
|
613
|
+
if (!step || this.locked)
|
|
614
|
+
return;
|
|
615
|
+
ev.preventDefault();
|
|
616
|
+
ev.stopPropagation();
|
|
617
|
+
const by = ev.shiftKey ? 15 : 1;
|
|
618
|
+
const now = figureSurfaceAnglesOf(surface, surface.place);
|
|
619
|
+
if (surface.form === 'around') {
|
|
620
|
+
if (!step[0])
|
|
621
|
+
return;
|
|
622
|
+
this.change({ surface: this.placeOf(surface, { around: now.around + step[0] * by }) });
|
|
623
|
+
}
|
|
624
|
+
else
|
|
625
|
+
this.change({ surface: this.placeOf(surface, { azimuth: now.azimuth + step[0] * by, elevation: Math.max(-90, Math.min(90, now.elevation + step[1] * by)) }) });
|
|
626
|
+
this.released();
|
|
627
|
+
}
|
|
416
628
|
};
|
|
417
629
|
__decorate([
|
|
418
630
|
property(),
|
|
@@ -470,6 +682,18 @@ __decorate([
|
|
|
470
682
|
property(),
|
|
471
683
|
__metadata("design:type", String)
|
|
472
684
|
], FigureFastenDrawing.prototype, "show", void 0);
|
|
685
|
+
__decorate([
|
|
686
|
+
property(),
|
|
687
|
+
__metadata("design:type", String)
|
|
688
|
+
], FigureFastenDrawing.prototype, "surfaceForm", void 0);
|
|
689
|
+
__decorate([
|
|
690
|
+
property({ attribute: false }),
|
|
691
|
+
__metadata("design:type", Object)
|
|
692
|
+
], FigureFastenDrawing.prototype, "surface", void 0);
|
|
693
|
+
__decorate([
|
|
694
|
+
state(),
|
|
695
|
+
__metadata("design:type", Object)
|
|
696
|
+
], FigureFastenDrawing.prototype, "turning", void 0);
|
|
473
697
|
__decorate([
|
|
474
698
|
state(),
|
|
475
699
|
__metadata("design:type", Object)
|