@things-factory/figure-ui 10.1.45 → 10.1.47

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.
Files changed (138) hide show
  1. package/client/modeller/angle-dial.ts +70 -0
  2. package/client/modeller/figure-settings.ts +328 -0
  3. package/client/modeller/figure-v3-capability.ts +137 -0
  4. package/client/modeller/figure-v3-clips.ts +253 -0
  5. package/client/modeller/figure-v3-controls.ts +212 -0
  6. package/client/modeller/figure-v3-links.ts +150 -79
  7. package/client/modeller/figure-v3-material.ts +108 -35
  8. package/client/modeller/figure-v3-parts.ts +96 -3
  9. package/client/modeller/figure-v3-preview.ts +326 -0
  10. package/client/modeller/figure-v3-properties.ts +29 -57
  11. package/client/modeller/figure-v3-verdict.ts +598 -60
  12. package/client/modeller/figure-view.ts +152 -0
  13. package/client/modeller/side-panel-styles.ts +326 -0
  14. package/client/modeller/v3-canvas.ts +221 -263
  15. package/client/modeller/v3-clips.ts +89 -0
  16. package/client/modeller/v3-controls.ts +54 -0
  17. package/client/modeller/v3-editor.ts +532 -223
  18. package/client/modeller/v3-fields.ts +62 -0
  19. package/client/modeller/v3-help.ts +41 -0
  20. package/client/modeller/v3-keys.ts +34 -0
  21. package/client/modeller/v3-links.ts +126 -10
  22. package/client/modeller/v3-live.ts +79 -0
  23. package/client/modeller/v3-maturity.ts +415 -0
  24. package/client/modeller/v3-palette.ts +45 -0
  25. package/client/modeller/v3-preview-model.ts +54 -0
  26. package/client/modeller/v3-stage-model.ts +159 -0
  27. package/client/pages/figure-list-page.ts +4 -4
  28. package/client/pages/figure-v3-modeller-page.ts +66 -134
  29. package/dist-client/modeller/angle-dial.d.ts +32 -0
  30. package/dist-client/modeller/angle-dial.js +41 -0
  31. package/dist-client/modeller/angle-dial.js.map +1 -0
  32. package/dist-client/modeller/figure-settings.d.ts +39 -0
  33. package/dist-client/modeller/figure-settings.js +317 -0
  34. package/dist-client/modeller/figure-settings.js.map +1 -0
  35. package/dist-client/modeller/figure-v3-capability.d.ts +22 -0
  36. package/dist-client/modeller/figure-v3-capability.js +141 -0
  37. package/dist-client/modeller/figure-v3-capability.js.map +1 -0
  38. package/dist-client/modeller/figure-v3-clips.d.ts +31 -0
  39. package/dist-client/modeller/figure-v3-clips.js +268 -0
  40. package/dist-client/modeller/figure-v3-clips.js.map +1 -0
  41. package/dist-client/modeller/figure-v3-controls.d.ts +36 -0
  42. package/dist-client/modeller/figure-v3-controls.js +226 -0
  43. package/dist-client/modeller/figure-v3-controls.js.map +1 -0
  44. package/dist-client/modeller/figure-v3-links.d.ts +10 -2
  45. package/dist-client/modeller/figure-v3-links.js +134 -79
  46. package/dist-client/modeller/figure-v3-links.js.map +1 -1
  47. package/dist-client/modeller/figure-v3-material.d.ts +5 -2
  48. package/dist-client/modeller/figure-v3-material.js +109 -35
  49. package/dist-client/modeller/figure-v3-material.js.map +1 -1
  50. package/dist-client/modeller/figure-v3-parts.d.ts +10 -0
  51. package/dist-client/modeller/figure-v3-parts.js +88 -3
  52. package/dist-client/modeller/figure-v3-parts.js.map +1 -1
  53. package/dist-client/modeller/figure-v3-preview.d.ts +34 -0
  54. package/dist-client/modeller/figure-v3-preview.js +322 -0
  55. package/dist-client/modeller/figure-v3-preview.js.map +1 -0
  56. package/dist-client/modeller/figure-v3-properties.d.ts +2 -2
  57. package/dist-client/modeller/figure-v3-properties.js +29 -57
  58. package/dist-client/modeller/figure-v3-properties.js.map +1 -1
  59. package/dist-client/modeller/figure-v3-verdict.d.ts +31 -17
  60. package/dist-client/modeller/figure-v3-verdict.js +579 -59
  61. package/dist-client/modeller/figure-v3-verdict.js.map +1 -1
  62. package/dist-client/modeller/figure-view.d.ts +118 -0
  63. package/dist-client/modeller/figure-view.js +78 -0
  64. package/dist-client/modeller/figure-view.js.map +1 -0
  65. package/dist-client/modeller/side-panel-styles.d.ts +23 -0
  66. package/dist-client/modeller/side-panel-styles.js +326 -0
  67. package/dist-client/modeller/side-panel-styles.js.map +1 -0
  68. package/dist-client/modeller/v3-canvas.d.ts +29 -37
  69. package/dist-client/modeller/v3-canvas.js +188 -260
  70. package/dist-client/modeller/v3-canvas.js.map +1 -1
  71. package/dist-client/modeller/v3-clips.d.ts +39 -0
  72. package/dist-client/modeller/v3-clips.js +58 -0
  73. package/dist-client/modeller/v3-clips.js.map +1 -0
  74. package/dist-client/modeller/v3-controls.d.ts +28 -0
  75. package/dist-client/modeller/v3-controls.js +28 -0
  76. package/dist-client/modeller/v3-controls.js.map +1 -0
  77. package/dist-client/modeller/v3-editor.d.ts +58 -1
  78. package/dist-client/modeller/v3-editor.js +556 -218
  79. package/dist-client/modeller/v3-editor.js.map +1 -1
  80. package/dist-client/modeller/v3-fields.d.ts +30 -0
  81. package/dist-client/modeller/v3-fields.js +46 -0
  82. package/dist-client/modeller/v3-fields.js.map +1 -0
  83. package/dist-client/modeller/v3-help.d.ts +18 -0
  84. package/dist-client/modeller/v3-help.js +37 -0
  85. package/dist-client/modeller/v3-help.js.map +1 -0
  86. package/dist-client/modeller/v3-keys.d.ts +14 -0
  87. package/dist-client/modeller/v3-keys.js +23 -0
  88. package/dist-client/modeller/v3-keys.js.map +1 -0
  89. package/dist-client/modeller/v3-links.d.ts +44 -2
  90. package/dist-client/modeller/v3-links.js +125 -8
  91. package/dist-client/modeller/v3-links.js.map +1 -1
  92. package/dist-client/modeller/v3-live.d.ts +31 -0
  93. package/dist-client/modeller/v3-live.js +58 -0
  94. package/dist-client/modeller/v3-live.js.map +1 -0
  95. package/dist-client/modeller/v3-maturity.d.ts +120 -0
  96. package/dist-client/modeller/v3-maturity.js +317 -0
  97. package/dist-client/modeller/v3-maturity.js.map +1 -0
  98. package/dist-client/modeller/v3-palette.d.ts +7 -0
  99. package/dist-client/modeller/v3-palette.js +42 -0
  100. package/dist-client/modeller/v3-palette.js.map +1 -0
  101. package/dist-client/modeller/v3-preview-model.d.ts +32 -0
  102. package/dist-client/modeller/v3-preview-model.js +48 -0
  103. package/dist-client/modeller/v3-preview-model.js.map +1 -0
  104. package/dist-client/modeller/v3-stage-model.d.ts +31 -0
  105. package/dist-client/modeller/v3-stage-model.js +121 -0
  106. package/dist-client/modeller/v3-stage-model.js.map +1 -0
  107. package/dist-client/pages/figure-list-page.js +4 -4
  108. package/dist-client/pages/figure-list-page.js.map +1 -1
  109. package/dist-client/pages/figure-v3-modeller-page.d.ts +2 -6
  110. package/dist-client/pages/figure-v3-modeller-page.js +64 -136
  111. package/dist-client/pages/figure-v3-modeller-page.js.map +1 -1
  112. package/dist-client/tsconfig.chk.tsbuildinfo +1 -0
  113. package/dist-client/tsconfig.scratch-fm.tsbuildinfo +1 -0
  114. package/dist-client/tsconfig.tsbuildinfo +1 -1
  115. package/package.json +6 -6
  116. package/test/v3-clips.test.ts +70 -0
  117. package/test/v3-controls.test.ts +68 -0
  118. package/test/v3-fields.test.ts +62 -0
  119. package/test/v3-gizmo.test.ts +3 -5
  120. package/test/v3-keys.test.ts +37 -0
  121. package/test/v3-layout.test.ts +78 -0
  122. package/test/v3-links.test.ts +118 -7
  123. package/test/v3-live.test.ts +99 -0
  124. package/test/v3-material.test.ts +6 -0
  125. package/test/v3-maturity.test.ts +268 -0
  126. package/test/v3-parts-wiring.test.ts +3 -1
  127. package/test/v3-preview.test.ts +42 -0
  128. package/test/v3-properties.test.ts +4 -2
  129. package/test/v3-scene-canvas.test.ts +85 -0
  130. package/test/v3-stage-model.test.ts +25 -0
  131. package/test/v3-theme.test.ts +16 -25
  132. package/test/v3-verdict.test.ts +12 -6
  133. package/test/v3-view.test.ts +20 -0
  134. package/translations/en.json +98 -5
  135. package/translations/ja.json +100 -7
  136. package/translations/ko.json +98 -5
  137. package/translations/ms.json +100 -7
  138. package/translations/zh.json +100 -7
@@ -428,12 +428,12 @@ export class FigureListPage extends FigureListPageBase {
428
428
  카드에 남긴 하나뿐인 숫자. **이름표를 달지 않으므로** 무엇인지는 손이 갔을 때 뜨는
429
429
  말이 알려 준다.
430
430
 
431
- 색칠한 배지로 두지 않는다. 지금 카탈로그의 열넷 중 열셋이 0 점이라(선언된 묶음 한도
432
- 3 을 넘긴다) 붉은 덩어리가 카드마다 서면 목록이 시끄럽고, 그러면서 아무것도 가르지
433
- 못한다. 숫자는 조용히 적고 낮은 것에만 **점 하나**를 붙인다.
431
+ 색칠한 배지로 두지 않는다. 옛 draw call 한도 3 으로 재던 때는 카탈로그 거의 모두가 0 점이라
432
+ 붉은 덩어리가 카드마다 섰고 아무것도 가르지 못했다. V3 는 「한 화면 N 대」 목표에 견준
433
+ 여유라(`v3ScoreOf`, 2026-09-24) 퍼지지만, 숫자는 조용히 적고 낮은 것에만 **점 하나**를 붙인다.
434
434
 
435
435
  아직 재지 않은 것을 0 으로 보여 주지 않는다 — 0 은 「가볍다」는 뜻이 되어 버린다.
436
- 등급 문자(A~D)도 여기서 만들지 않는다: 경계는 `figure-model` 의 `scoreOf` 가 정하고,
436
+ 등급 문자(A~D)도 여기서 만들지 않는다: 경계는 `figure-model` 의 `scoreOf` · `v3ScoreOf` 가 정하고,
437
437
  화면이 그것을 베끼면 두 벌이 되어 목록과 저작면이 다른 등급을 말한다.
438
438
  */
439
439
  renderer: (value: number | null) =>
@@ -12,6 +12,7 @@ import '@material/web/icon/icon.js'
12
12
  import '../modeller/figure-history-panel.js'
13
13
  import '../modeller/figure-v3-verdict.js'
14
14
  import '../modeller/figure-v3-properties.js'
15
+ import type { V3BudgetLine } from '../modeller/v3-maturity.js'
15
16
 
16
17
  /**
17
18
  * The V3 product page has exactly one authoritative workspace for UI and AI input transactions.
@@ -39,31 +40,25 @@ export class FigureV3ModellerPage extends PageView {
39
40
  min-width: 0;
40
41
  min-height: 0;
41
42
  }
42
- aside {
43
- width: 320px;
44
- flex: none;
45
- min-height: 0;
46
- overflow: auto;
47
- display: flex;
48
- flex-direction: column;
49
- border-left: 1px solid var(--md-sys-color-outline-variant);
50
- }
43
+ /* The first field of the properties tab, in the side panel's look (side-panel-styles): a label above the field. */
51
44
  label[type-field] {
52
45
  display: grid;
53
- gap: 4px;
54
- padding: 12px 12px 8px;
55
- font-size: 12px;
56
- border-bottom: 1px solid var(--md-sys-color-outline-variant);
46
+ gap: 2px;
47
+ margin: 0 0 5px;
48
+ font-size: 0.68rem;
49
+ color: var(--md-sys-color-on-surface-variant);
57
50
  }
58
51
  label[type-field] input,
59
52
  label[type-field] code {
60
- font: inherit;
61
- font-family: monospace;
62
- padding: 6px 8px;
63
- border: 1px solid var(--md-sys-color-outline-variant);
64
- border-radius: 4px;
65
- background: var(--md-sys-color-surface);
53
+ box-sizing: border-box;
54
+ min-height: 30px;
55
+ padding: 4px 7px;
56
+ font-family: var(--mono-font, monospace);
57
+ font-size: 0.76rem;
66
58
  color: var(--md-sys-color-on-surface);
59
+ background: var(--md-sys-color-surface-container-lowest);
60
+ border: 1px solid var(--md-sys-color-outline-variant);
61
+ border-radius: 6px;
67
62
  }
68
63
  label[type-field] small {
69
64
  color: var(--md-sys-color-on-surface-variant);
@@ -77,57 +72,9 @@ export class FigureV3ModellerPage extends PageView {
77
72
  label[type-field] small[role='alert'] {
78
73
  color: var(--md-sys-color-error);
79
74
  }
80
- /* The V2 side panel's tabs, drawn the same way: one icon per tab, the name in title and aria-label. */
81
- div[tabs] {
82
- display: flex;
83
- flex: none;
84
- border-bottom: 1px solid var(--md-sys-color-outline-variant);
85
- }
86
- button[tab] {
87
- flex: 1;
88
- position: relative;
89
- display: flex;
90
- align-items: center;
91
- justify-content: center;
92
- padding: 7px 6px;
93
- color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
94
- background: none;
95
- border: none;
96
- border-bottom: 2px solid transparent;
97
- cursor: pointer;
98
- }
99
- button[tab]:hover:not([on]) {
100
- background-color: var(--md-sys-color-surface-container);
101
- }
102
- button[tab][on] {
103
- color: var(--md-sys-color-primary);
104
- border-bottom-color: var(--md-sys-color-primary);
105
- }
106
- button[tab] md-icon {
107
- font-size: 20px;
108
- width: 20px;
109
- height: 20px;
110
- }
111
- span[badge] {
112
- position: absolute;
113
- top: 5px;
114
- right: 2px;
115
- padding: 0 5px;
116
- font-size: 0.62rem;
117
- font-weight: 700;
118
- line-height: 1.5;
119
- color: var(--md-sys-color-on-primary-container);
120
- background-color: var(--md-sys-color-primary-container);
121
- border-radius: 999em;
122
- pointer-events: none;
123
- }
124
- /* Hidden, not removed: the verdict keeps its last answer and the panel its list while the other tab is open. */
125
- [off] {
126
- display: none;
127
- }
128
75
  .error {
129
76
  padding: 16px;
130
- color: #922716;
77
+ color: var(--md-sys-color-error);
131
78
  }
132
79
  `
133
80
  private readonly session = createV3ProductSession(v3ProductStore)
@@ -149,12 +96,9 @@ export class FigureV3ModellerPage extends PageView {
149
96
  @state() private typeError = ''
150
97
  /** Why a command from the side did nothing. Shown beside the tabs — the editor stays, since nothing in it was lost. */
151
98
  @state() private commandError = ''
152
- /**
153
- * Which tab the side shows. The verdict comes first: it is what the author needs while editing, and the count on
154
- * its tab stays in sight while the history is open — as on the V2 page.
155
- */
156
- @state() private tab: 'properties' | 'verdict' | 'history' = 'verdict'
99
+ /** The verdict's count, handed to the editor's verdict tab. */
157
100
  @state() private instances?: number
101
+ @state() private budget?: V3BudgetLine
158
102
  /**
159
103
  * The source the verdict judges. The session refuses to export while it loads or saves, so the last one read is
160
104
  * kept rather than blanked — the verdict would otherwise flicker to 「waiting」 on every save.
@@ -364,66 +308,54 @@ export class FigureV3ModellerPage extends PageView {
364
308
  render() {
365
309
  if (this.error) return html`<p role="alert" class="error">${this.error}</p>`
366
310
  const view = this.session.read()
367
- return html`<figure-v3-editor
368
- .session=${this.session}
369
- .revision=${this.revision}
370
- @v3-changed=${this.changed}
371
- ></figure-v3-editor>
372
- <aside>
373
- <label type-field>
374
- <span>${i18next.t('figure.label.figure-type')}</span>
375
- ${this.row.version > 0
376
- ? html`<code>${this.row.type}</code><small>${i18next.t('figure.text.type-name-cannot-change')}</small>`
377
- : html`<input
378
- .value=${this.row.type ?? ''}
379
- placeholder=${i18next.t('figure.text.figure-type-placeholder')}
380
- ?disabled=${!view.id}
381
- @change=${this.renameType}
382
- />`}
383
- ${this.typeError ? html`<small role="alert">${this.typeError}</small>` : ''}
384
- </label>
385
- ${this.commandError ? html`<p fit-error role="alert">${this.commandError}</p>` : ''}
386
- <div tabs>
387
- ${this.renderTab('properties', 'tune', i18next.t('figure.label.properties'))}
388
- ${this.renderTab('verdict', 'insights', i18next.t('figure.label.maturity'), this.instances)}
389
- ${this.renderTab('history', 'history', i18next.t('figure.label.history'))}
390
- </div>
391
- <figure-v3-properties
392
- ?off=${this.tab !== 'properties'}
393
- .source=${this.draftSource()}
394
- .figureId=${view.id}
395
- .figureCategory=${this.row.category}
396
- .figureTags=${this.row.tags}
397
- @v3-command=${this.onCommand}
398
- @v3-catalog=${this.onCatalog}
399
- ></figure-v3-properties>
400
- <figure-v3-verdict
401
- ?off=${this.tab !== 'verdict'}
402
- .source=${this.draftSource()}
403
- .figureId=${view.id}
404
- .figureType=${this.row.type}
405
- @capacity-changed=${(event: CustomEvent) => (this.instances = event.detail.instances)}
406
- @fit-base-to-parts=${this.fitToParts}
407
- ></figure-v3-verdict>
408
- <figure-history-panel
409
- ?off=${this.tab !== 'history'}
410
- format="v3"
411
- .figureId=${view.id}
412
- .figureState=${this.row.state}
413
- .figureVersion=${this.row.version}
414
- .figureType=${this.row.type}
415
- .dirty=${!!view.dirty}
416
- @fit-base-to-parts=${this.fitToParts}
417
- @figure-released=${this.released}
418
- @figure-reverted=${this.reverted}
419
- ></figure-history-panel>
420
- </aside>`
421
- }
422
- private renderTab(tab: 'properties' | 'verdict' | 'history', icon: string, label: string, badge?: number) {
423
- return html`
424
- <button tab ?on=${this.tab === tab} title=${label} aria-label=${label} @click=${() => (this.tab = tab)}>
425
- <md-icon>${icon}</md-icon>${badge == null ? '' : html`<span badge>${badge.toLocaleString()}</span>`}
426
- </button>
427
- `
311
+ return html`<figure-v3-editor .session=${this.session} .revision=${this.revision} .instances=${this.instances} .budget=${this.budget} @v3-changed=${this.changed}>
312
+ ${this.commandError ? html`<p slot="notice" fit-error role="alert">${this.commandError}</p>` : ''}
313
+ <figure-v3-properties
314
+ slot="figure"
315
+ .source=${this.draftSource()}
316
+ .figureId=${view.id}
317
+ .figureCategory=${this.row.category}
318
+ .figureTags=${this.row.tags}
319
+ @v3-command=${this.onCommand}
320
+ @v3-catalog=${this.onCatalog}
321
+ >
322
+ <label slot="type" type-field>
323
+ <span>${i18next.t('figure.label.figure-type')}</span>
324
+ ${this.row.version > 0
325
+ ? html`<code>${this.row.type}</code><small>${i18next.t('figure.text.type-name-cannot-change')}</small>`
326
+ : html`<input
327
+ .value=${this.row.type ?? ''}
328
+ placeholder=${i18next.t('figure.text.figure-type-placeholder')}
329
+ ?disabled=${!view.id}
330
+ @change=${this.renameType}
331
+ />`}
332
+ ${this.typeError ? html`<small role="alert">${this.typeError}</small>` : ''}
333
+ </label>
334
+ </figure-v3-properties>
335
+ <figure-v3-verdict
336
+ slot="verdict"
337
+ .source=${this.draftSource()}
338
+ .figureId=${view.id}
339
+ .figureType=${this.row.type}
340
+ @capacity-changed=${(event: CustomEvent) => {
341
+ this.instances = event.detail.instances
342
+ this.budget = event.detail.budget
343
+ }}
344
+ @fit-base-to-parts=${this.fitToParts}
345
+ ></figure-v3-verdict>
346
+ <figure-history-panel
347
+ slot="history"
348
+ format="v3"
349
+ .figureId=${view.id}
350
+ .figureState=${this.row.state}
351
+ .figureVersion=${this.row.version}
352
+ .figureType=${this.row.type}
353
+ .dirty=${!!view.dirty}
354
+ @fit-base-to-parts=${this.fitToParts}
355
+ @figure-released=${this.released}
356
+ @figure-reverted=${this.reverted}
357
+ ></figure-history-panel>
358
+ </figure-v3-editor>`
428
359
  }
360
+
429
361
  }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * 막대 옆에 서는 **각도 눈**. 지금 각이 범위의 어디인지를 한 눈에 보인다.
3
+ *
4
+ * ## 왜 3D 로는 모자랐나
5
+ *
6
+ * 관절이 돌아도 화면이 그대로인 경우가 있다 — 제 축에서 대칭인 부품이 그렇다. 그래서 관절이
7
+ * 모는 부품에 바늘을 달아 미리보기에서 함께 돌게 했는데(`joint-gizmo.ts` 의 `jointNeedles`),
8
+ * **미리보기에서는 그 바늘이 4 × 2 픽셀이다**(잰 값: 부품 100mm · 바늘 60 × 12mm · 여덟 대를
9
+ * 한 화면에 세운 상태). 미리보기는 크기 반응을 보려고 여덟 대를 나란히 놓는 자리라 한 대가
10
+ * 20 픽셀쯤이고, 그 위의 어떤 표시도 몇 픽셀을 넘지 못한다.
11
+ *
12
+ * 각을 읽는 일은 3D 의 배율에서 떼어 놓는다. 눈은 막대 옆 24 픽셀 자리에 서고, 도형이 아무리
13
+ * 작게 서 있어도 같은 크기로 읽힌다.
14
+ */
15
+ export interface DialShape {
16
+ /** 가동 범위를 채운 부채꼴. SVG path 의 `d`. */
17
+ sector: string;
18
+ /** 지금 값이 가리키는 끝점. */
19
+ needle: {
20
+ x: number;
21
+ y: number;
22
+ };
23
+ centre: {
24
+ x: number;
25
+ y: number;
26
+ };
27
+ radius: number;
28
+ }
29
+ /**
30
+ * 눈의 모양. 값이 범위를 벗어나면 범위 끝에 세운다 — 밖을 가리키는 바늘은 없는 값을 말한다.
31
+ */
32
+ export declare function dialShape(min: number, max: number, value: number, radius?: number): DialShape;
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Copyright © HatioLab Inc. All rights reserved.
3
+ */
4
+ /** 0 도가 위를 가리키고, 값이 커지면 시계 방향으로 돈다 — 화면의 각과 같은 방향이다. */
5
+ function at(centre, radius, degrees) {
6
+ const rad = (degrees * Math.PI) / 180;
7
+ return {
8
+ x: +(centre.x + radius * Math.sin(rad)).toFixed(2),
9
+ y: +(centre.y - radius * Math.cos(rad)).toFixed(2)
10
+ };
11
+ }
12
+ /** 한 바퀴에 가까우면 부채꼴 대신 온전한 원이다. */
13
+ const FULL = 359.9;
14
+ /**
15
+ * 눈의 모양. 값이 범위를 벗어나면 범위 끝에 세운다 — 밖을 가리키는 바늘은 없는 값을 말한다.
16
+ */
17
+ export function dialShape(min, max, value, radius = 9) {
18
+ const centre = { x: radius + 1, y: radius + 1 };
19
+ const span = Math.abs(max - min);
20
+ const held = Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max));
21
+ if (span >= FULL) {
22
+ const top = at(centre, radius, 0);
23
+ const bottom = at(centre, radius, 180);
24
+ return {
25
+ sector: `M ${top.x} ${top.y} A ${radius} ${radius} 0 1 1 ${bottom.x} ${bottom.y} A ${radius} ${radius} 0 1 1 ${top.x} ${top.y} Z`,
26
+ needle: at(centre, radius, held),
27
+ centre,
28
+ radius
29
+ };
30
+ }
31
+ const from = at(centre, radius, min);
32
+ const to = at(centre, radius, max);
33
+ const large = span > 180 ? 1 : 0;
34
+ return {
35
+ sector: `M ${centre.x} ${centre.y} L ${from.x} ${from.y} A ${radius} ${radius} 0 ${large} 1 ${to.x} ${to.y} Z`,
36
+ needle: at(centre, radius, held),
37
+ centre,
38
+ radius
39
+ };
40
+ }
41
+ //# sourceMappingURL=angle-dial.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"angle-dial.js","sourceRoot":"","sources":["../../client/modeller/angle-dial.ts"],"names":[],"mappings":"AAAA;;GAEG;AA0BH,wDAAwD;AACxD,SAAS,EAAE,CAAC,MAAgC,EAAE,MAAc,EAAE,OAAe;IAC3E,MAAM,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAA;IACrC,OAAO;QACL,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QAClD,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;KACnD,CAAA;AACH,CAAC;AAED,iCAAiC;AACjC,MAAM,IAAI,GAAG,KAAK,CAAA;AAElB;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,GAAW,EAAE,KAAa,EAAE,MAAM,GAAG,CAAC;IAC3E,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAAA;IAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAA;IAChC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;IAE9E,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;QACjC,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;QACtC,OAAO;YACL,MAAM,EAAE,KAAK,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,MAAM,IAAI,MAAM,UAAU,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,MAAM,IAAI,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI;YACjI,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC;YAChC,MAAM;YACN,MAAM;SACP,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;IAClC,MAAM,KAAK,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAEhC,OAAO;QACL,MAAM,EAAE,KAAK,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,MAAM,IAAI,MAAM,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI;QAC9G,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC;QAChC,MAAM;QACN,MAAM;KACP,CAAA;AACH,CAAC","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\n/**\n * 막대 옆에 서는 **각도 눈**. 지금 각이 범위의 어디인지를 한 눈에 보인다.\n *\n * ## 왜 3D 로는 모자랐나\n *\n * 관절이 돌아도 화면이 그대로인 경우가 있다 — 제 축에서 대칭인 부품이 그렇다. 그래서 관절이\n * 모는 부품에 바늘을 달아 미리보기에서 함께 돌게 했는데(`joint-gizmo.ts` 의 `jointNeedles`),\n * **미리보기에서는 그 바늘이 4 × 2 픽셀이다**(잰 값: 부품 100mm · 바늘 60 × 12mm · 여덟 대를\n * 한 화면에 세운 상태). 미리보기는 크기 반응을 보려고 여덟 대를 나란히 놓는 자리라 한 대가\n * 20 픽셀쯤이고, 그 위의 어떤 표시도 몇 픽셀을 넘지 못한다.\n *\n * 각을 읽는 일은 3D 의 배율에서 떼어 놓는다. 눈은 막대 옆 24 픽셀 자리에 서고, 도형이 아무리\n * 작게 서 있어도 같은 크기로 읽힌다.\n */\n\nexport interface DialShape {\n /** 가동 범위를 채운 부채꼴. SVG path 의 `d`. */\n sector: string\n /** 지금 값이 가리키는 끝점. */\n needle: { x: number; y: number }\n centre: { x: number; y: number }\n radius: number\n}\n\n/** 0 도가 위를 가리키고, 값이 커지면 시계 방향으로 돈다 — 화면의 각과 같은 방향이다. */\nfunction at(centre: { x: number; y: number }, radius: number, degrees: number) {\n const rad = (degrees * Math.PI) / 180\n return {\n x: +(centre.x + radius * Math.sin(rad)).toFixed(2),\n y: +(centre.y - radius * Math.cos(rad)).toFixed(2)\n }\n}\n\n/** 한 바퀴에 가까우면 부채꼴 대신 온전한 원이다. */\nconst FULL = 359.9\n\n/**\n * 눈의 모양. 값이 범위를 벗어나면 범위 끝에 세운다 — 밖을 가리키는 바늘은 없는 값을 말한다.\n */\nexport function dialShape(min: number, max: number, value: number, radius = 9): DialShape {\n const centre = { x: radius + 1, y: radius + 1 }\n const span = Math.abs(max - min)\n const held = Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max))\n\n if (span >= FULL) {\n const top = at(centre, radius, 0)\n const bottom = at(centre, radius, 180)\n return {\n sector: `M ${top.x} ${top.y} A ${radius} ${radius} 0 1 1 ${bottom.x} ${bottom.y} A ${radius} ${radius} 0 1 1 ${top.x} ${top.y} Z`,\n needle: at(centre, radius, held),\n centre,\n radius\n }\n }\n\n const from = at(centre, radius, min)\n const to = at(centre, radius, max)\n const large = span > 180 ? 1 : 0\n\n return {\n sector: `M ${centre.x} ${centre.y} L ${from.x} ${from.y} A ${radius} ${radius} 0 ${large} 1 ${to.x} ${to.y} Z`,\n needle: at(centre, radius, held),\n centre,\n radius\n }\n}\n"]}
@@ -0,0 +1,39 @@
1
+ import { LitElement } from 'lit';
2
+ import type { ViewSettings } from './figure-view.js';
3
+ declare const FigureSettings_base: (new (...args: any[]) => LitElement) & typeof LitElement;
4
+ /**
5
+ * 저작 화면의 **보기 설정**.
6
+ *
7
+ * ## 자산이 아니라 작업대다
8
+ *
9
+ * 여기서 고치는 것은 저장되지 않는다. 조명을 밝게 하고 바닥을 켠 것은 지금 보기 편한
10
+ * 상태일 뿐이다. 그래서 「저장 안 됨」을 화면에 적어 둔다 — 안 적으면 저작자가 조명을
11
+ * 맞춰 두고 그것이 자산에 딸려 간다고 여긴다.
12
+ *
13
+ * ## 값을 들고 있지 않는다
14
+ *
15
+ * 이 패널은 받은 것을 그리고 바뀐 것을 알린다. 정본은 모델러 페이지가 갖는다 — 속성
16
+ * 패널과 같은 방식이다. 여기서 들고 있으면 페이지가 다시 그릴 때 두 벌이 갈린다.
17
+ */
18
+ export declare class FigureSettings extends FigureSettings_base {
19
+ static styles: import("lit").CSSResult[];
20
+ view: ViewSettings;
21
+ render(): import("lit-html").TemplateResult<1>;
22
+ private toggle;
23
+ private slider;
24
+ /** 처음 값으로 되돌린다. 만지다 길을 잃었을 때 돌아올 자리가 있어야 한다. */
25
+ private reset;
26
+ private put;
27
+ /**
28
+ * 바뀐 것을 알린다.
29
+ *
30
+ * **알리기 전에 내 것도 바꿔 둔다.** Lit 은 속성을 다음 렌더에 넣으므로, 같은 프레임에
31
+ * 두 번 고치면 두 번째가 `this.view` 의 옛 값을 읽어 첫 번째를 덮는다. 실제로 그랬다 —
32
+ * 축 가이드를 끄고 바닥판을 켰더니 축 가이드가 도로 켜져 있었고, 화면의 체크 상자와
33
+ * 씬의 상태가 서로 다른 말을 했다.
34
+ *
35
+ * 정본은 여전히 모델러 페이지가 갖는다. 여기 값은 다음 렌더에 같은 것으로 덮인다.
36
+ */
37
+ private tell;
38
+ }
39
+ export {};