@operato/property-panel 10.29.46 → 10.29.48
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/CHANGELOG.md +17 -0
- package/dist/src/property-panel/shapes/shapes.d.ts +10 -0
- package/dist/src/property-panel/shapes/shapes.js +117 -0
- package/dist/src/property-panel/shapes/shapes.js.map +1 -1
- package/dist/test/drawing-size.test.d.ts +1 -0
- package/dist/test/drawing-size.test.js +48 -0
- package/dist/test/drawing-size.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/test/drawing-size.test.ts +54 -0
- package/translations/en.json +9 -1
- package/translations/es.json +9 -1
- package/translations/ja.json +9 -1
- package/translations/ko.json +9 -1
- package/translations/ms.json +9 -1
- package/translations/zh.json +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
### [10.29.48](https://github.com/hatiolab/operato/compare/v10.29.47...v10.29.48) (2026-10-22)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @operato/property-panel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### [10.29.47](https://github.com/hatiolab/operato/compare/v10.29.46...v10.29.47) (2026-10-21)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### :rocket: New Features
|
|
18
|
+
|
|
19
|
+
* **property-panel:** the drawing's size and unit on the root (ADR-0144 2.4) ([e9e965d](https://github.com/hatiolab/operato/commit/e9e965d3ce4770211df7b8be3255a8fb0345026e))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
6
23
|
### [10.29.46](https://github.com/hatiolab/operato/compare/v10.29.45...v10.29.46) (2026-10-20)
|
|
7
24
|
|
|
8
25
|
**Note:** Version bump only for package @operato/property-panel
|
|
@@ -15,8 +15,18 @@ export declare class PropertyShapes extends AbstractProperty {
|
|
|
15
15
|
bounds: BOUNDS | null;
|
|
16
16
|
selected: Component[];
|
|
17
17
|
private _positionExpanded;
|
|
18
|
+
private _calibrating;
|
|
18
19
|
firstUpdated(): void;
|
|
19
20
|
render(): import("lit-html").TemplateResult<1>;
|
|
21
|
+
/**
|
|
22
|
+
* 「도면 크기와 단위」 (ADR-0144 2.4): the drawing's real size and ceiling height in the unit it is shown in, and that
|
|
23
|
+
* unit. Stored as the scale and coordinates only -- a real width typed sets the width in coordinates through the scale.
|
|
24
|
+
* A drawing whose scale is unknown says so and offers 「실제 길이로 맞추기」: the real length of its width sets the
|
|
25
|
+
* scale, and no coordinate moves.
|
|
26
|
+
*/
|
|
27
|
+
private renderDrawingSize;
|
|
28
|
+
private emitProperty;
|
|
29
|
+
private emitBounds;
|
|
20
30
|
private renderHeading;
|
|
21
31
|
onValueChange(e: Event): void;
|
|
22
32
|
_hasTextProperty(selected: Component[]): boolean;
|
|
@@ -10,6 +10,8 @@ import '@operato/help/ox-title-with-help.js';
|
|
|
10
10
|
import { css, html } from 'lit';
|
|
11
11
|
import { property, state } from 'lit/decorators.js';
|
|
12
12
|
import { keyed } from 'lit/directives/keyed.js';
|
|
13
|
+
import { DRAWING_DISPLAY_UNITS, calibratedMmPerUnit, displayToMm, drawingScaleOf, mmToDisplay } from '@hatiolab/things-scene';
|
|
14
|
+
import { i18next } from '@operato/i18n';
|
|
13
15
|
import { PropertyGridStyles } from '@operato/styles/property-grid-styles.js';
|
|
14
16
|
import { BoxPaddingEditorStyles } from '@operato/styles/box-padding-editor-styles.js';
|
|
15
17
|
import { AbstractProperty } from '../abstract-property.js';
|
|
@@ -27,6 +29,8 @@ export class PropertyShapes extends AbstractProperty {
|
|
|
27
29
|
this.bounds = null;
|
|
28
30
|
this.selected = [];
|
|
29
31
|
this._positionExpanded = false;
|
|
32
|
+
/* 「실제 길이로 맞추기」 open: the drawing's width is asked its real length. */
|
|
33
|
+
this._calibrating = false;
|
|
30
34
|
}
|
|
31
35
|
firstUpdated() {
|
|
32
36
|
this.renderRoot.addEventListener('change', this.onValueChange.bind(this));
|
|
@@ -226,6 +230,7 @@ export class PropertyShapes extends AbstractProperty {
|
|
|
226
230
|
typeof this.selected[0].isRootModel === 'function' &&
|
|
227
231
|
this.selected[0].isRootModel()
|
|
228
232
|
? html `
|
|
233
|
+
${this.renderDrawingSize(value)}
|
|
229
234
|
<fieldset class="icon-label">
|
|
230
235
|
<legend>
|
|
231
236
|
<ox-title-with-help topic="board-modeller/shapes/viewer-option" msgid="label.viewer-option"
|
|
@@ -266,6 +271,80 @@ export class PropertyShapes extends AbstractProperty {
|
|
|
266
271
|
: html ``}
|
|
267
272
|
`;
|
|
268
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* 「도면 크기와 단위」 (ADR-0144 2.4): the drawing's real size and ceiling height in the unit it is shown in, and that
|
|
276
|
+
* unit. Stored as the scale and coordinates only -- a real width typed sets the width in coordinates through the scale.
|
|
277
|
+
* A drawing whose scale is unknown says so and offers 「실제 길이로 맞추기」: the real length of its width sets the
|
|
278
|
+
* scale, and no coordinate moves.
|
|
279
|
+
*/
|
|
280
|
+
renderDrawingSize(value) {
|
|
281
|
+
const scale = drawingScaleOf(value);
|
|
282
|
+
const { width = 0, height = 0 } = (this.bounds || {});
|
|
283
|
+
const heights = value.heights || {};
|
|
284
|
+
const ceiling = typeof heights.ceiling === 'number' && Number.isFinite(heights.ceiling) ? heights.ceiling : 3000;
|
|
285
|
+
const shown = (mm) => fmtNumber(mmToDisplay(mm, scale));
|
|
286
|
+
const typed = (e) => e.target.valueAsNumber;
|
|
287
|
+
const unit = html `<span>${scale.displayUnit}</span>`;
|
|
288
|
+
return html `
|
|
289
|
+
<fieldset class="icon-label" drawing-size>
|
|
290
|
+
<legend><ox-i18n msgid="label.drawing-size-and-unit">drawing size and unit</ox-i18n></legend>
|
|
291
|
+
<div class="property-grid">
|
|
292
|
+
<label><ox-i18n msgid="label.display-unit">unit</ox-i18n></label>
|
|
293
|
+
<select drawing-unit .value=${scale.displayUnit} @change=${(e) => this.emitProperty({ displayUnit: e.target.value })}>
|
|
294
|
+
${DRAWING_DISPLAY_UNITS.map(u => html `<option value=${u} ?selected=${u === scale.displayUnit}>${u}</option>`)}
|
|
295
|
+
</select>
|
|
296
|
+
${scale.known
|
|
297
|
+
? html `
|
|
298
|
+
<label><ox-i18n msgid="label.drawing-width">width</ox-i18n></label>
|
|
299
|
+
<div class="field" drawing>
|
|
300
|
+
<input drawing-width type="number" .value=${shown(width * scale.mmPerUnit)}
|
|
301
|
+
@change=${(e) => this.emitBounds({ width: displayToMm(typed(e), scale) / scale.mmPerUnit })} />${unit}
|
|
302
|
+
</div>
|
|
303
|
+
<label><ox-i18n msgid="label.drawing-depth">depth</ox-i18n></label>
|
|
304
|
+
<div class="field" drawing>
|
|
305
|
+
<input drawing-depth type="number" .value=${shown(height * scale.mmPerUnit)}
|
|
306
|
+
@change=${(e) => this.emitBounds({ height: displayToMm(typed(e), scale) / scale.mmPerUnit })} />${unit}
|
|
307
|
+
</div>
|
|
308
|
+
<label><ox-i18n msgid="label.ceiling-height">ceiling</ox-i18n></label>
|
|
309
|
+
<div class="field" drawing>
|
|
310
|
+
<input drawing-ceiling type="number" .value=${shown(ceiling)}
|
|
311
|
+
@change=${(e) => {
|
|
312
|
+
const mm = displayToMm(typed(e), scale);
|
|
313
|
+
if (Number.isFinite(mm) && mm > 0)
|
|
314
|
+
this.emitProperty({ heights: { ...heights, ceiling: mm } });
|
|
315
|
+
}} />${unit}
|
|
316
|
+
</div>
|
|
317
|
+
`
|
|
318
|
+
: html `<span scale-unknown><ox-i18n msgid="text.scale-unknown">scale unknown</ox-i18n></span>`}
|
|
319
|
+
${this._calibrating
|
|
320
|
+
? html `
|
|
321
|
+
<span calibrate-question>${i18next.t('label.calibrate-width', { width: fmtNumber(width) })}</span>
|
|
322
|
+
<div class="field" drawing>
|
|
323
|
+
<input calibrate-length type="number"
|
|
324
|
+
@change=${(e) => {
|
|
325
|
+
const mmPerUnit = calibratedMmPerUnit(Number(width), displayToMm(typed(e), scale));
|
|
326
|
+
if (mmPerUnit === undefined)
|
|
327
|
+
return;
|
|
328
|
+
this._calibrating = false;
|
|
329
|
+
this.emitProperty({ mmPerUnit });
|
|
330
|
+
}} />${unit}
|
|
331
|
+
</div>
|
|
332
|
+
`
|
|
333
|
+
: html `<button calibrate type="button" @click=${() => (this._calibrating = true)}>
|
|
334
|
+
<ox-i18n msgid="button.calibrate-scale">fit to a real length</ox-i18n>
|
|
335
|
+
</button>`}
|
|
336
|
+
</div>
|
|
337
|
+
</fieldset>
|
|
338
|
+
`;
|
|
339
|
+
}
|
|
340
|
+
emitProperty(detail) {
|
|
341
|
+
this.dispatchEvent(new CustomEvent('property-change', { bubbles: true, composed: true, detail }));
|
|
342
|
+
}
|
|
343
|
+
emitBounds(detail) {
|
|
344
|
+
if (Object.values(detail).some(v => !(Number.isFinite(v) && v > 0)))
|
|
345
|
+
return;
|
|
346
|
+
this.dispatchEvent(new CustomEvent('bounds-change', { bubbles: true, composed: true, detail }));
|
|
347
|
+
}
|
|
269
348
|
renderHeading(rootSelected, value) {
|
|
270
349
|
var _a;
|
|
271
350
|
if (rootSelected) {
|
|
@@ -378,6 +457,41 @@ PropertyShapes.styles = [
|
|
|
378
457
|
PropertyGridStyles,
|
|
379
458
|
BoxPaddingEditorStyles,
|
|
380
459
|
css `
|
|
460
|
+
/* 「도면 크기와 단위」 (ADR-0144): a value with its unit in the editor column, as the W · H fields are. */
|
|
461
|
+
.property-grid > .field[drawing] {
|
|
462
|
+
grid-column: 10 / -1;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.property-grid > [scale-unknown] {
|
|
466
|
+
grid-column: 10 / -1;
|
|
467
|
+
align-self: center;
|
|
468
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
469
|
+
font-size: 0.74rem;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.property-grid > [calibrate-question] {
|
|
473
|
+
grid-column: 1 / -1;
|
|
474
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
475
|
+
font-size: 0.74rem;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.property-grid > [calibrate-question] + .field[drawing] {
|
|
479
|
+
grid-column: 1 / -1;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/* A quiet text action: no box, the accent ink. */
|
|
483
|
+
.property-grid > button[calibrate] {
|
|
484
|
+
grid-column: 10 / -1;
|
|
485
|
+
justify-self: start;
|
|
486
|
+
width: auto;
|
|
487
|
+
padding: 2px 0;
|
|
488
|
+
border: 0;
|
|
489
|
+
background: none;
|
|
490
|
+
color: var(--md-sys-color-primary);
|
|
491
|
+
font: inherit;
|
|
492
|
+
font-size: 0.74rem;
|
|
493
|
+
cursor: pointer;
|
|
494
|
+
}
|
|
381
495
|
`
|
|
382
496
|
];
|
|
383
497
|
__decorate([
|
|
@@ -395,4 +509,7 @@ __decorate([
|
|
|
395
509
|
__decorate([
|
|
396
510
|
state()
|
|
397
511
|
], PropertyShapes.prototype, "_positionExpanded", void 0);
|
|
512
|
+
__decorate([
|
|
513
|
+
state()
|
|
514
|
+
], PropertyShapes.prototype, "_calibrating", void 0);
|
|
398
515
|
//# sourceMappingURL=shapes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shapes.js","sourceRoot":"","sources":["../../../../src/property-panel/shapes/shapes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/input/ox-input-angle.js'\nimport '@operato/input/ox-buttons-radio.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/i18n/ox-i18n.js'\nimport '@operato/help/ox-title-with-help.js'\n\nimport { css, html } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { keyed } from 'lit/directives/keyed.js'\n\nimport { BOUNDS, Component, Properties } from '@hatiolab/things-scene'\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\nimport { BoxPaddingEditorStyles } from '@operato/styles/box-padding-editor-styles.js'\n\nimport { AbstractProperty } from '../abstract-property.js'\n\n/** A coordinate as the panel shows it: at most two decimals, never the float's full tail. */\nfunction fmtNumber(value: unknown): string {\n const n = typeof value === 'number' ? value : parseFloat(String(value ?? ''))\n return Number.isFinite(n) ? String(Math.round(n * 100) / 100) : ''\n}\n\nexport class PropertyShapes extends AbstractProperty {\n static styles = [\n css`\n /* What is selected: the board's name for the root, kind and name for a shape. */\n [heading] {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 12px 14px 4px;\n line-height: 1.3;\n white-space: nowrap;\n overflow: hidden;\n }\n\n [heading] b {\n font-size: 0.92rem;\n font-weight: 600;\n color: var(--md-sys-color-on-surface);\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n [heading] small {\n font-size: 0.7rem;\n font-weight: 500;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-outline);\n overflow: hidden;\n text-overflow: ellipsis;\n }\n `,\n PropertyGridStyles,\n BoxPaddingEditorStyles,\n css`\n `\n ]\n\n @property({ type: Object }) value?: Properties\n /* The name of the thing being modelled (a board, a figure). Drawn at the top of this tab when\n * the root is what is selected - the modeller page has no title row of its own any more. */\n @property({ type: String }) heading: string = ''\n @property({ type: Object }) bounds: BOUNDS | null = null\n @property({ type: Array }) selected: Component[] = []\n\n @state() private _positionExpanded: boolean = false\n\n firstUpdated() {\n this.renderRoot.addEventListener('change', this.onValueChange.bind(this))\n }\n\n render() {\n const value = this.value || {}\n const { width = '', height = '' } = this.bounds || {}\n\n const rootSelected =\n !!this.selected.length &&\n typeof this.selected[0].isRootModel === 'function' &&\n this.selected[0].isRootModel()\n\n return html`\n ${this.renderHeading(rootSelected, value)}\n <fieldset>\n <div class=\"property-grid\">\n ${this._isIdentifiable(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.id\">ID</ox-i18n> </label>\n <input value-key=\"id\" .value=${value.id || ''} />\n `\n : html``}\n ${this._isClassIdentifiable(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.class\">Class</ox-i18n> </label>\n <input value-key=\"class\" .value=${value.class || ''} />\n `\n : html``}\n ${this._hasTextProperty(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.text\">Text</ox-i18n> </label>\n <input value-key=\"text\" .value=${value.text || ''} />\n <label> <ox-i18n msgid=\"label.text-format\">Text Format</ox-i18n> </label>\n <input value-key=\"textFormat\" .value=${value.textFormat || ''} list=\"format-list\" />\n <datalist id=\"format-list\">\n <option value=\"#,###.\"></option>\n <option value=\"#,###.#\"></option>\n <option value=\"#,###.0\"></option>\n <option value=\"#,##0.#\"></option>\n <option value=\"#,##0.0\"></option>\n <option value=\"#,##0.0%\"></option>\n </datalist>\n `\n : html``}\n ${this._hasProperties(this.selected)\n ? html`\n <input id=\"checkbox-hidden\" value-key=\"hidden\" type=\"checkbox\" .checked=${value.hidden} />\n <label for=\"checkbox-hidden\"> <ox-i18n msgid=\"label.item-hidden\">Item Hidden</ox-i18n> </label>\n\n <input id=\"checkbox-locked\" value-key=\"locked\" type=\"checkbox\" .checked=${value.locked} />\n <label for=\"checkbox-locked\"> <ox-i18n msgid=\"label.locked\">Locked</ox-i18n> </label>\n `\n : html``}\n </div>\n </fieldset>\n\n ${!this._isLine(this.selected)\n ? keyed(\n this.selected,\n html`\n <fieldset class=\"icon-label\">\n <legend>\n <ox-title-with-help topic=\"board-modeller/shapes/size\" msgid=\"label.size\">size</ox-title-with-help>\n </legend>\n\n <div class=\"property-grid\">\n <div class=\"field half\" title=\"width\">\n <span>W</span>\n <input type=\"number\" value-key=\"bounds.width\" .value=${fmtNumber(width)} />\n </div>\n <div class=\"field half\" title=\"height\">\n <span>H</span>\n <input type=\"number\" value-key=\"bounds.height\" .value=${fmtNumber(height)} />\n </div>\n\n ${this.selected.length &&\n this.selected[0] &&\n typeof this.selected[0].isRootModel === 'function' &&\n this.selected[0].isRootModel()\n ? html``\n : html`\n <label class=\"rotate\"><ox-i18n msgid=\"label.rotate\">rotate</ox-i18n></label>\n <ox-input-angle value-key=\"rotation\" .value=${value.rotation ?? 0}> </ox-input-angle>\n `}\n </div>\n </fieldset>\n `\n )\n : html``}\n ${this._isPositionable(this.selected)\n ? keyed(\n this.selected,\n html`\n <fieldset class=\"icon-label\" collapsable ?collapsed=${!this._positionExpanded}>\n <legend\n @click=${(e: Event) => {\n this._positionExpanded = !this._positionExpanded\n }}\n >\n <ox-title-with-help topic=\"board-modeller/shapes/position\" msgid=\"label.position\"\n >position</ox-title-with-help\n >\n <md-icon>${this._positionExpanded ? 'expand_less' : 'expand_more'}</md-icon>\n </legend>\n\n <div class=\"property-grid\">\n <label>Position</label>\n <select value-key=\"position\" .value=${value.position}>\n <option value=\"\"> </option>\n <option value=\"static\">static</option>\n <option value=\"relative\">relative</option>\n <option value=\"absolute\">absolute</option>\n <option value=\"fixed\">fixed</option>\n <option value=\"sticky\">sticky</option>\n <option value=\"popup\">popup (template)</option>\n </select>\n\n <label>Origin</label>\n <select value-key=\"origin\" .value=${value.origin}>\n <option value=\"\"> </option>\n <option value=\"left-top\">left-top</option>\n <option value=\"center-top\">center-top</option>\n <option value=\"right-top\">right-top</option>\n <option value=\"left-middle\">left-middle</option>\n <option value=\"center-middle\">center-middle</option>\n <option value=\"right-middle\">right-middle</option>\n <option value=\"left-bottom\">left-bottom</option>\n <option value=\"center-bottom\">center-bottom</option>\n <option value=\"right-bottom\">right-bottom</option>\n </select>\n\n <label> <ox-i18n msgid=\"label.offset-x\">offset-X</ox-i18n> </label>\n <input type=\"number\" value-key=\"offsetX\" .value=${String(value.offsetX ?? '')} />\n <label> <ox-i18n msgid=\"label.offset-y\">offset-Y</ox-i18n> </label>\n <input type=\"number\" value-key=\"offsetY\" .value=${String(value.offsetY ?? '')} />\n </div>\n </fieldset>\n `\n )\n : html``}\n ${this._hasTextProperty(this.selected)\n ? html`\n <fieldset>\n <legend>\n <ox-title-with-help topic=\"board-modeller/shapes/text-box\" msgid=\"label.text-box\"\n >text box</ox-title-with-help\n >\n </legend>\n\n <div class=\"property-grid\">\n <label> <ox-i18n msgid=\"label.horizontal\">horizontal</ox-i18n> </label>\n <ox-buttons-radio value-key=\"textAlign\" .value=${value.textAlign}>\n <md-icon data-value=\"left\">format_align_left</md-icon>\n <md-icon data-value=\"center\">format_align_center</md-icon>\n <md-icon data-value=\"right\">format_align_right</md-icon>\n <md-icon data-value=\"justify\">format_align_justify</md-icon>\n </ox-buttons-radio>\n\n <label> <ox-i18n msgid=\"label.vertical\">vertical</ox-i18n> </label>\n <ox-buttons-radio value-key=\"textBaseline\" .value=${value.textBaseline}>\n <md-icon data-value=\"top\">align_vertical_top</md-icon>\n <md-icon data-value=\"middle\">align_vertical_center</md-icon>\n <md-icon data-value=\"bottom\">align_vertical_bottom</md-icon>\n </ox-buttons-radio>\n\n <input\n id=\"checkbox-support-markdown\"\n type=\"checkbox\"\n value-key=\"supportMarkdown\"\n .checked=${value.supportMarkdown}\n />\n <label for=\"checkbox-support-markdown\">\n <ox-i18n msgid=\"label.support-markdown\">Support Markdown</ox-i18n>\n </label>\n\n <input id=\"checkbox-textwrap\" type=\"checkbox\" value-key=\"textWrap\" .checked=${value.textWrap} />\n <label for=\"checkbox-textwrap\"> <ox-i18n msgid=\"label.text-wrap\">Text Wrap</ox-i18n> </label>\n\n ${!value.textWrap\n ? html` <label for=\"checkbox-textOverflow\">\n <ox-i18n msgid=\"label.text-overflow\">Text Overflow</ox-i18n>\n </label>\n <select value-key=\"textOverflow\" .value=${value.textOverflow || ''}>\n <option value=\"\" selected>none</option>\n <option value=\"ellipsis\">ellipsis</option>\n <option value=\"clip\">clip</option>\n </select>`\n : ''}\n\n <label> <ox-i18n msgid=\"label.padding\">padding</ox-i18n> </label>\n <div class=\"box-padding custom-editor\">\n <input class=\"top\" type=\"number\" value-key=\"paddingTop\" .value=${value.paddingTop || 0} />\n <input class=\"left\" type=\"number\" value-key=\"paddingLeft\" .value=${value.paddingLeft || 0} />\n <div class=\"inner\"></div>\n <input class=\"right\" type=\"number\" value-key=\"paddingRight\" .value=${value.paddingRight || 0} />\n <input class=\"bottom\" type=\"number\" value-key=\"paddingBottom\" .value=${value.paddingBottom || 0} />\n </div>\n </div>\n </fieldset>\n `\n : html``}\n ${this.selected.length &&\n this.selected[0] &&\n typeof this.selected[0].isRootModel === 'function' &&\n this.selected[0].isRootModel()\n ? html`\n <fieldset class=\"icon-label\">\n <legend>\n <ox-title-with-help topic=\"board-modeller/shapes/viewer-option\" msgid=\"label.viewer-option\"\n >Viewer Option</ox-title-with-help\n >\n </legend>\n\n <div class=\"property-grid\">\n <label><ox-i18n msgid=\"label.fit\">Fit</ox-i18n></label>\n <select value-key=\"fitMode\" .value=${value.fitMode || 'ratio'}>\n <option value=\"none\">none</option>\n <option value=\"center\">center</option>\n <option value=\"ratio\" selected>ratio</option>\n <option value=\"both\">both</option>\n <option value=\"width\">width</option>\n <option value=\"height\">height</option>\n </select>\n </div>\n </fieldset>\n <fieldset class=\"icon-label\">\n <legend>\n <ox-title-with-help topic=\"board-modeller/shapes/print-option\" msgid=\"label.label-print\"\n >Print Option</ox-title-with-help\n >\n </legend>\n\n <div class=\"property-grid\">\n <label class=\"rotate\"><ox-i18n msgid=\"label.label-rotation\">Label Rotation</ox-i18n></label>\n <select value-key=\"labelRotation\" .value=${value.labelRotation || 'N'}>\n <option value=\"N\" selected>0°</option>\n <option value=\"B\">90°</option>\n <option value=\"I\">180°</option>\n <option value=\"R\">270°</option>\n </select>\n </div>\n </fieldset>\n `\n : html``}\n `\n }\n\n private renderHeading(rootSelected: boolean, value: any) {\n if (rootSelected) {\n return this.heading ? html`<div heading title=${this.heading}><b>${this.heading}</b></div>` : html``\n }\n\n const selected = this.selected || []\n if (!selected.length) {\n return html``\n }\n\n if (selected.length > 1) {\n return html`<div heading><b>${selected.length} items</b></div>`\n }\n\n const component: any = selected[0]\n const kind = String(component.get?.('type') || '')\n const name = String(value?.id || value?.text || '')\n\n return html`<div heading title=${name || kind}><b>${name || kind}</b>${name ? html`<small>${kind}</small>` : html``}</div>`\n }\n\n onValueChange(e: Event) {\n var element = e.target as HTMLElement\n var key = element.getAttribute('value-key')\n\n if (!key) {\n return\n }\n\n var value = this.getValueFromEventTarget(element)\n\n if (key.indexOf('bounds.') == 0) {\n if (isNaN(value)) return\n this.dispatchEvent(\n new CustomEvent('bounds-change', {\n bubbles: true,\n composed: true,\n detail: {\n [key.substr(7)]: value\n }\n })\n )\n } else {\n this.onAfterValueChange(key, value)\n }\n }\n\n _hasTextProperty(selected: Component[]) {\n for (let i = 0; i < selected.length; i++) {\n if (!selected[i] || !selected[i].hasTextProperty) return false\n }\n\n return true\n }\n\n _hasProperties(selected: Component[]) {\n if (\n !selected ||\n selected.length == 0 ||\n (selected[0] && typeof selected[0].isLayer === 'function' && selected[0].isLayer())\n )\n return false\n\n return true\n }\n\n _isIdentifiable(selected: Component[]) {\n if (\n !selected ||\n selected.length == 0 ||\n selected.length > 1 ||\n !selected[0] ||\n (typeof selected[0].isLayer === 'function' && selected[0].isLayer())\n )\n return false\n\n return true\n }\n\n _isClassIdentifiable(selected: Component[]) {\n if (!selected || (selected[0] && typeof selected[0].isLayer === 'function' && selected[0].isLayer())) return false\n\n return true\n }\n\n _isLine(selected: Component[]) {\n if (!selected || !(selected[0] && typeof selected[0].isLine === 'function' && selected[0].isLine())) return false\n\n return true\n }\n\n _isPositionable(selected: Component[]) {\n if (!selected || !(selected[0] && typeof selected[0].isPositionable === 'function' && selected[0].isPositionable()))\n return false\n\n return true\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"shapes.js","sourceRoot":"","sources":["../../../../src/property-panel/shapes/shapes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/input/ox-input-angle.js'\nimport '@operato/input/ox-buttons-radio.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/i18n/ox-i18n.js'\nimport '@operato/help/ox-title-with-help.js'\n\nimport { css, html } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { keyed } from 'lit/directives/keyed.js'\n\nimport { BOUNDS, Component, Properties, DRAWING_DISPLAY_UNITS, calibratedMmPerUnit, displayToMm, drawingScaleOf, mmToDisplay } from '@hatiolab/things-scene'\nimport { i18next } from '@operato/i18n'\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\nimport { BoxPaddingEditorStyles } from '@operato/styles/box-padding-editor-styles.js'\n\nimport { AbstractProperty } from '../abstract-property.js'\n\n/** A coordinate as the panel shows it: at most two decimals, never the float's full tail. */\nfunction fmtNumber(value: unknown): string {\n const n = typeof value === 'number' ? value : parseFloat(String(value ?? ''))\n return Number.isFinite(n) ? String(Math.round(n * 100) / 100) : ''\n}\n\nexport class PropertyShapes extends AbstractProperty {\n static styles = [\n css`\n /* What is selected: the board's name for the root, kind and name for a shape. */\n [heading] {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 12px 14px 4px;\n line-height: 1.3;\n white-space: nowrap;\n overflow: hidden;\n }\n\n [heading] b {\n font-size: 0.92rem;\n font-weight: 600;\n color: var(--md-sys-color-on-surface);\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n [heading] small {\n font-size: 0.7rem;\n font-weight: 500;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-outline);\n overflow: hidden;\n text-overflow: ellipsis;\n }\n `,\n PropertyGridStyles,\n BoxPaddingEditorStyles,\n css`\n /* 「도면 크기와 단위」 (ADR-0144): a value with its unit in the editor column, as the W · H fields are. */\n .property-grid > .field[drawing] {\n grid-column: 10 / -1;\n }\n\n .property-grid > [scale-unknown] {\n grid-column: 10 / -1;\n align-self: center;\n color: var(--md-sys-color-on-surface-variant);\n font-size: 0.74rem;\n }\n\n .property-grid > [calibrate-question] {\n grid-column: 1 / -1;\n color: var(--md-sys-color-on-surface-variant);\n font-size: 0.74rem;\n }\n\n .property-grid > [calibrate-question] + .field[drawing] {\n grid-column: 1 / -1;\n }\n\n /* A quiet text action: no box, the accent ink. */\n .property-grid > button[calibrate] {\n grid-column: 10 / -1;\n justify-self: start;\n width: auto;\n padding: 2px 0;\n border: 0;\n background: none;\n color: var(--md-sys-color-primary);\n font: inherit;\n font-size: 0.74rem;\n cursor: pointer;\n }\n `\n ]\n\n @property({ type: Object }) value?: Properties\n /* The name of the thing being modelled (a board, a figure). Drawn at the top of this tab when\n * the root is what is selected - the modeller page has no title row of its own any more. */\n @property({ type: String }) heading: string = ''\n @property({ type: Object }) bounds: BOUNDS | null = null\n @property({ type: Array }) selected: Component[] = []\n\n @state() private _positionExpanded: boolean = false\n /* 「실제 길이로 맞추기」 open: the drawing's width is asked its real length. */\n @state() private _calibrating: boolean = false\n\n firstUpdated() {\n this.renderRoot.addEventListener('change', this.onValueChange.bind(this))\n }\n\n render() {\n const value = this.value || {}\n const { width = '', height = '' } = this.bounds || {}\n\n const rootSelected =\n !!this.selected.length &&\n typeof this.selected[0].isRootModel === 'function' &&\n this.selected[0].isRootModel()\n\n return html`\n ${this.renderHeading(rootSelected, value)}\n <fieldset>\n <div class=\"property-grid\">\n ${this._isIdentifiable(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.id\">ID</ox-i18n> </label>\n <input value-key=\"id\" .value=${value.id || ''} />\n `\n : html``}\n ${this._isClassIdentifiable(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.class\">Class</ox-i18n> </label>\n <input value-key=\"class\" .value=${value.class || ''} />\n `\n : html``}\n ${this._hasTextProperty(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.text\">Text</ox-i18n> </label>\n <input value-key=\"text\" .value=${value.text || ''} />\n <label> <ox-i18n msgid=\"label.text-format\">Text Format</ox-i18n> </label>\n <input value-key=\"textFormat\" .value=${value.textFormat || ''} list=\"format-list\" />\n <datalist id=\"format-list\">\n <option value=\"#,###.\"></option>\n <option value=\"#,###.#\"></option>\n <option value=\"#,###.0\"></option>\n <option value=\"#,##0.#\"></option>\n <option value=\"#,##0.0\"></option>\n <option value=\"#,##0.0%\"></option>\n </datalist>\n `\n : html``}\n ${this._hasProperties(this.selected)\n ? html`\n <input id=\"checkbox-hidden\" value-key=\"hidden\" type=\"checkbox\" .checked=${value.hidden} />\n <label for=\"checkbox-hidden\"> <ox-i18n msgid=\"label.item-hidden\">Item Hidden</ox-i18n> </label>\n\n <input id=\"checkbox-locked\" value-key=\"locked\" type=\"checkbox\" .checked=${value.locked} />\n <label for=\"checkbox-locked\"> <ox-i18n msgid=\"label.locked\">Locked</ox-i18n> </label>\n `\n : html``}\n </div>\n </fieldset>\n\n ${!this._isLine(this.selected)\n ? keyed(\n this.selected,\n html`\n <fieldset class=\"icon-label\">\n <legend>\n <ox-title-with-help topic=\"board-modeller/shapes/size\" msgid=\"label.size\">size</ox-title-with-help>\n </legend>\n\n <div class=\"property-grid\">\n <div class=\"field half\" title=\"width\">\n <span>W</span>\n <input type=\"number\" value-key=\"bounds.width\" .value=${fmtNumber(width)} />\n </div>\n <div class=\"field half\" title=\"height\">\n <span>H</span>\n <input type=\"number\" value-key=\"bounds.height\" .value=${fmtNumber(height)} />\n </div>\n\n ${this.selected.length &&\n this.selected[0] &&\n typeof this.selected[0].isRootModel === 'function' &&\n this.selected[0].isRootModel()\n ? html``\n : html`\n <label class=\"rotate\"><ox-i18n msgid=\"label.rotate\">rotate</ox-i18n></label>\n <ox-input-angle value-key=\"rotation\" .value=${value.rotation ?? 0}> </ox-input-angle>\n `}\n </div>\n </fieldset>\n `\n )\n : html``}\n ${this._isPositionable(this.selected)\n ? keyed(\n this.selected,\n html`\n <fieldset class=\"icon-label\" collapsable ?collapsed=${!this._positionExpanded}>\n <legend\n @click=${(e: Event) => {\n this._positionExpanded = !this._positionExpanded\n }}\n >\n <ox-title-with-help topic=\"board-modeller/shapes/position\" msgid=\"label.position\"\n >position</ox-title-with-help\n >\n <md-icon>${this._positionExpanded ? 'expand_less' : 'expand_more'}</md-icon>\n </legend>\n\n <div class=\"property-grid\">\n <label>Position</label>\n <select value-key=\"position\" .value=${value.position}>\n <option value=\"\"> </option>\n <option value=\"static\">static</option>\n <option value=\"relative\">relative</option>\n <option value=\"absolute\">absolute</option>\n <option value=\"fixed\">fixed</option>\n <option value=\"sticky\">sticky</option>\n <option value=\"popup\">popup (template)</option>\n </select>\n\n <label>Origin</label>\n <select value-key=\"origin\" .value=${value.origin}>\n <option value=\"\"> </option>\n <option value=\"left-top\">left-top</option>\n <option value=\"center-top\">center-top</option>\n <option value=\"right-top\">right-top</option>\n <option value=\"left-middle\">left-middle</option>\n <option value=\"center-middle\">center-middle</option>\n <option value=\"right-middle\">right-middle</option>\n <option value=\"left-bottom\">left-bottom</option>\n <option value=\"center-bottom\">center-bottom</option>\n <option value=\"right-bottom\">right-bottom</option>\n </select>\n\n <label> <ox-i18n msgid=\"label.offset-x\">offset-X</ox-i18n> </label>\n <input type=\"number\" value-key=\"offsetX\" .value=${String(value.offsetX ?? '')} />\n <label> <ox-i18n msgid=\"label.offset-y\">offset-Y</ox-i18n> </label>\n <input type=\"number\" value-key=\"offsetY\" .value=${String(value.offsetY ?? '')} />\n </div>\n </fieldset>\n `\n )\n : html``}\n ${this._hasTextProperty(this.selected)\n ? html`\n <fieldset>\n <legend>\n <ox-title-with-help topic=\"board-modeller/shapes/text-box\" msgid=\"label.text-box\"\n >text box</ox-title-with-help\n >\n </legend>\n\n <div class=\"property-grid\">\n <label> <ox-i18n msgid=\"label.horizontal\">horizontal</ox-i18n> </label>\n <ox-buttons-radio value-key=\"textAlign\" .value=${value.textAlign}>\n <md-icon data-value=\"left\">format_align_left</md-icon>\n <md-icon data-value=\"center\">format_align_center</md-icon>\n <md-icon data-value=\"right\">format_align_right</md-icon>\n <md-icon data-value=\"justify\">format_align_justify</md-icon>\n </ox-buttons-radio>\n\n <label> <ox-i18n msgid=\"label.vertical\">vertical</ox-i18n> </label>\n <ox-buttons-radio value-key=\"textBaseline\" .value=${value.textBaseline}>\n <md-icon data-value=\"top\">align_vertical_top</md-icon>\n <md-icon data-value=\"middle\">align_vertical_center</md-icon>\n <md-icon data-value=\"bottom\">align_vertical_bottom</md-icon>\n </ox-buttons-radio>\n\n <input\n id=\"checkbox-support-markdown\"\n type=\"checkbox\"\n value-key=\"supportMarkdown\"\n .checked=${value.supportMarkdown}\n />\n <label for=\"checkbox-support-markdown\">\n <ox-i18n msgid=\"label.support-markdown\">Support Markdown</ox-i18n>\n </label>\n\n <input id=\"checkbox-textwrap\" type=\"checkbox\" value-key=\"textWrap\" .checked=${value.textWrap} />\n <label for=\"checkbox-textwrap\"> <ox-i18n msgid=\"label.text-wrap\">Text Wrap</ox-i18n> </label>\n\n ${!value.textWrap\n ? html` <label for=\"checkbox-textOverflow\">\n <ox-i18n msgid=\"label.text-overflow\">Text Overflow</ox-i18n>\n </label>\n <select value-key=\"textOverflow\" .value=${value.textOverflow || ''}>\n <option value=\"\" selected>none</option>\n <option value=\"ellipsis\">ellipsis</option>\n <option value=\"clip\">clip</option>\n </select>`\n : ''}\n\n <label> <ox-i18n msgid=\"label.padding\">padding</ox-i18n> </label>\n <div class=\"box-padding custom-editor\">\n <input class=\"top\" type=\"number\" value-key=\"paddingTop\" .value=${value.paddingTop || 0} />\n <input class=\"left\" type=\"number\" value-key=\"paddingLeft\" .value=${value.paddingLeft || 0} />\n <div class=\"inner\"></div>\n <input class=\"right\" type=\"number\" value-key=\"paddingRight\" .value=${value.paddingRight || 0} />\n <input class=\"bottom\" type=\"number\" value-key=\"paddingBottom\" .value=${value.paddingBottom || 0} />\n </div>\n </div>\n </fieldset>\n `\n : html``}\n ${this.selected.length &&\n this.selected[0] &&\n typeof this.selected[0].isRootModel === 'function' &&\n this.selected[0].isRootModel()\n ? html`\n ${this.renderDrawingSize(value)}\n <fieldset class=\"icon-label\">\n <legend>\n <ox-title-with-help topic=\"board-modeller/shapes/viewer-option\" msgid=\"label.viewer-option\"\n >Viewer Option</ox-title-with-help\n >\n </legend>\n\n <div class=\"property-grid\">\n <label><ox-i18n msgid=\"label.fit\">Fit</ox-i18n></label>\n <select value-key=\"fitMode\" .value=${value.fitMode || 'ratio'}>\n <option value=\"none\">none</option>\n <option value=\"center\">center</option>\n <option value=\"ratio\" selected>ratio</option>\n <option value=\"both\">both</option>\n <option value=\"width\">width</option>\n <option value=\"height\">height</option>\n </select>\n </div>\n </fieldset>\n <fieldset class=\"icon-label\">\n <legend>\n <ox-title-with-help topic=\"board-modeller/shapes/print-option\" msgid=\"label.label-print\"\n >Print Option</ox-title-with-help\n >\n </legend>\n\n <div class=\"property-grid\">\n <label class=\"rotate\"><ox-i18n msgid=\"label.label-rotation\">Label Rotation</ox-i18n></label>\n <select value-key=\"labelRotation\" .value=${value.labelRotation || 'N'}>\n <option value=\"N\" selected>0°</option>\n <option value=\"B\">90°</option>\n <option value=\"I\">180°</option>\n <option value=\"R\">270°</option>\n </select>\n </div>\n </fieldset>\n `\n : html``}\n `\n }\n\n /**\n * 「도면 크기와 단위」 (ADR-0144 2.4): the drawing's real size and ceiling height in the unit it is shown in, and that\n * unit. Stored as the scale and coordinates only -- a real width typed sets the width in coordinates through the scale.\n * A drawing whose scale is unknown says so and offers 「실제 길이로 맞추기」: the real length of its width sets the\n * scale, and no coordinate moves.\n */\n private renderDrawingSize(value: any) {\n const scale = drawingScaleOf(value)\n const { width = 0, height = 0 } = (this.bounds || {}) as { width?: number; height?: number }\n const heights = value.heights || {}\n const ceiling = typeof heights.ceiling === 'number' && Number.isFinite(heights.ceiling) ? heights.ceiling : 3000\n const shown = (mm: number) => fmtNumber(mmToDisplay(mm, scale))\n const typed = (e: Event) => (e.target as HTMLInputElement).valueAsNumber\n const unit = html`<span>${scale.displayUnit}</span>`\n return html`\n <fieldset class=\"icon-label\" drawing-size>\n <legend><ox-i18n msgid=\"label.drawing-size-and-unit\">drawing size and unit</ox-i18n></legend>\n <div class=\"property-grid\">\n <label><ox-i18n msgid=\"label.display-unit\">unit</ox-i18n></label>\n <select drawing-unit .value=${scale.displayUnit} @change=${(e: Event) => this.emitProperty({ displayUnit: (e.target as HTMLSelectElement).value })}>\n ${DRAWING_DISPLAY_UNITS.map(u => html`<option value=${u} ?selected=${u === scale.displayUnit}>${u}</option>`)}\n </select>\n ${scale.known\n ? html`\n <label><ox-i18n msgid=\"label.drawing-width\">width</ox-i18n></label>\n <div class=\"field\" drawing>\n <input drawing-width type=\"number\" .value=${shown(width * scale.mmPerUnit)}\n @change=${(e: Event) => this.emitBounds({ width: displayToMm(typed(e), scale) / scale.mmPerUnit })} />${unit}\n </div>\n <label><ox-i18n msgid=\"label.drawing-depth\">depth</ox-i18n></label>\n <div class=\"field\" drawing>\n <input drawing-depth type=\"number\" .value=${shown(height * scale.mmPerUnit)}\n @change=${(e: Event) => this.emitBounds({ height: displayToMm(typed(e), scale) / scale.mmPerUnit })} />${unit}\n </div>\n <label><ox-i18n msgid=\"label.ceiling-height\">ceiling</ox-i18n></label>\n <div class=\"field\" drawing>\n <input drawing-ceiling type=\"number\" .value=${shown(ceiling)}\n @change=${(e: Event) => {\n const mm = displayToMm(typed(e), scale)\n if (Number.isFinite(mm) && mm > 0) this.emitProperty({ heights: { ...heights, ceiling: mm } })\n }} />${unit}\n </div>\n `\n : html`<span scale-unknown><ox-i18n msgid=\"text.scale-unknown\">scale unknown</ox-i18n></span>`}\n ${this._calibrating\n ? html`\n <span calibrate-question>${i18next.t('label.calibrate-width', { width: fmtNumber(width) })}</span>\n <div class=\"field\" drawing>\n <input calibrate-length type=\"number\"\n @change=${(e: Event) => {\n const mmPerUnit = calibratedMmPerUnit(Number(width), displayToMm(typed(e), scale))\n if (mmPerUnit === undefined) return\n this._calibrating = false\n this.emitProperty({ mmPerUnit })\n }} />${unit}\n </div>\n `\n : html`<button calibrate type=\"button\" @click=${() => (this._calibrating = true)}>\n <ox-i18n msgid=\"button.calibrate-scale\">fit to a real length</ox-i18n>\n </button>`}\n </div>\n </fieldset>\n `\n }\n\n private emitProperty(detail: Record<string, unknown>) {\n this.dispatchEvent(new CustomEvent('property-change', { bubbles: true, composed: true, detail }))\n }\n\n private emitBounds(detail: Record<string, number>) {\n if (Object.values(detail).some(v => !(Number.isFinite(v) && v > 0))) return\n this.dispatchEvent(new CustomEvent('bounds-change', { bubbles: true, composed: true, detail }))\n }\n\n private renderHeading(rootSelected: boolean, value: any) {\n if (rootSelected) {\n return this.heading ? html`<div heading title=${this.heading}><b>${this.heading}</b></div>` : html``\n }\n\n const selected = this.selected || []\n if (!selected.length) {\n return html``\n }\n\n if (selected.length > 1) {\n return html`<div heading><b>${selected.length} items</b></div>`\n }\n\n const component: any = selected[0]\n const kind = String(component.get?.('type') || '')\n const name = String(value?.id || value?.text || '')\n\n return html`<div heading title=${name || kind}><b>${name || kind}</b>${name ? html`<small>${kind}</small>` : html``}</div>`\n }\n\n onValueChange(e: Event) {\n var element = e.target as HTMLElement\n var key = element.getAttribute('value-key')\n\n if (!key) {\n return\n }\n\n var value = this.getValueFromEventTarget(element)\n\n if (key.indexOf('bounds.') == 0) {\n if (isNaN(value)) return\n this.dispatchEvent(\n new CustomEvent('bounds-change', {\n bubbles: true,\n composed: true,\n detail: {\n [key.substr(7)]: value\n }\n })\n )\n } else {\n this.onAfterValueChange(key, value)\n }\n }\n\n _hasTextProperty(selected: Component[]) {\n for (let i = 0; i < selected.length; i++) {\n if (!selected[i] || !selected[i].hasTextProperty) return false\n }\n\n return true\n }\n\n _hasProperties(selected: Component[]) {\n if (\n !selected ||\n selected.length == 0 ||\n (selected[0] && typeof selected[0].isLayer === 'function' && selected[0].isLayer())\n )\n return false\n\n return true\n }\n\n _isIdentifiable(selected: Component[]) {\n if (\n !selected ||\n selected.length == 0 ||\n selected.length > 1 ||\n !selected[0] ||\n (typeof selected[0].isLayer === 'function' && selected[0].isLayer())\n )\n return false\n\n return true\n }\n\n _isClassIdentifiable(selected: Component[]) {\n if (!selected || (selected[0] && typeof selected[0].isLayer === 'function' && selected[0].isLayer())) return false\n\n return true\n }\n\n _isLine(selected: Component[]) {\n if (!selected || !(selected[0] && typeof selected[0].isLine === 'function' && selected[0].isLine())) return false\n\n return true\n }\n\n _isPositionable(selected: Component[]) {\n if (!selected || !(selected[0] && typeof selected[0].isPositionable === 'function' && selected[0].isPositionable()))\n return false\n\n return true\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 「도면 크기와 단위」 (ADR-0144 2.4): the drawing's real size shown and typed in its display unit, stored as the scale and
|
|
3
|
+
* coordinates; a drawing whose scale is unknown says so and is fitted to a real length without a coordinate moving.
|
|
4
|
+
*/
|
|
5
|
+
import { html } from 'lit';
|
|
6
|
+
import { fixture, expect, oneEvent } from '@open-wc/testing';
|
|
7
|
+
import { PropertyShapes } from '../src/property-panel/shapes/shapes.js';
|
|
8
|
+
customElements.define('drawing-size-under-test', class extends PropertyShapes {
|
|
9
|
+
});
|
|
10
|
+
const root = { isRootModel: () => true, isLayer: () => true };
|
|
11
|
+
async function panel(value, bounds = { left: 0, top: 0, width: 6000, height: 4000 }) {
|
|
12
|
+
return fixture(html `<drawing-size-under-test .value=${value} .bounds=${bounds} .selected=${[root]}></drawing-size-under-test>`);
|
|
13
|
+
}
|
|
14
|
+
const field = (el, attr) => el.shadowRoot.querySelector(`input[${attr}]`);
|
|
15
|
+
const type = (input, value) => {
|
|
16
|
+
input.value = value;
|
|
17
|
+
input.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
|
18
|
+
};
|
|
19
|
+
describe('the drawing size and unit (ADR-0144)', () => {
|
|
20
|
+
it('a drawing with a scale shows its real size and ceiling in its display unit', async () => {
|
|
21
|
+
const el = await panel({ mmPerUnit: 10, displayUnit: 'm', heights: { ceiling: 3000 } });
|
|
22
|
+
expect([field(el, 'drawing-width').value, field(el, 'drawing-depth').value, field(el, 'drawing-ceiling').value]).to.deep.equal(['60', '40', '3']);
|
|
23
|
+
expect(el.shadowRoot.querySelector('[scale-unknown]')).to.equal(null);
|
|
24
|
+
});
|
|
25
|
+
it('a real width typed sets the width in coordinates through the scale', async () => {
|
|
26
|
+
const el = await panel({ mmPerUnit: 10, displayUnit: 'm' });
|
|
27
|
+
setTimeout(() => type(field(el, 'drawing-width'), '70'));
|
|
28
|
+
const { detail } = await oneEvent(el, 'bounds-change');
|
|
29
|
+
expect(detail).to.deep.equal({ width: 7000 });
|
|
30
|
+
});
|
|
31
|
+
it('a ceiling typed is kept as a real length, in mm', async () => {
|
|
32
|
+
const el = await panel({ mmPerUnit: 10, displayUnit: 'm', heights: { floor: 0, ceiling: 3000 } });
|
|
33
|
+
setTimeout(() => type(field(el, 'drawing-ceiling'), '4.5'));
|
|
34
|
+
const { detail } = await oneEvent(el, 'property-change');
|
|
35
|
+
expect(detail).to.deep.equal({ heights: { floor: 0, ceiling: 4500 } });
|
|
36
|
+
});
|
|
37
|
+
it('a drawing whose scale is unknown says so, and the real length of its width sets the scale', async () => {
|
|
38
|
+
const el = await panel({ displayUnit: 'm' });
|
|
39
|
+
expect(el.shadowRoot.querySelector('[scale-unknown]')).to.not.equal(null);
|
|
40
|
+
expect(field(el, 'drawing-width')).to.equal(null);
|
|
41
|
+
el.shadowRoot.querySelector('button[calibrate]').click();
|
|
42
|
+
await el.updateComplete;
|
|
43
|
+
setTimeout(() => type(field(el, 'calibrate-length'), '60'));
|
|
44
|
+
const { detail } = await oneEvent(el, 'property-change');
|
|
45
|
+
expect(detail).to.deep.equal({ mmPerUnit: 10 });
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=drawing-size.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drawing-size.test.js","sourceRoot":"","sources":["../../test/drawing-size.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 「도면 크기와 단위」 (ADR-0144 2.4): the drawing's real size shown and typed in its display unit, stored as the scale and\n * coordinates; a drawing whose scale is unknown says so and is fitted to a real length without a coordinate moving.\n */\nimport { html } from 'lit'\nimport { fixture, expect, oneEvent } from '@open-wc/testing'\n\nimport { PropertyShapes } from '../src/property-panel/shapes/shapes.js'\n\ncustomElements.define('drawing-size-under-test', class extends PropertyShapes {})\n\nconst root = { isRootModel: () => true, isLayer: () => true }\n\nasync function panel(value: Record<string, unknown>, bounds = { left: 0, top: 0, width: 6000, height: 4000 }) {\n return fixture<PropertyShapes>(html`<drawing-size-under-test .value=${value} .bounds=${bounds} .selected=${[root]}></drawing-size-under-test>`)\n}\nconst field = (el: PropertyShapes, attr: string) => el.shadowRoot!.querySelector(`input[${attr}]`) as HTMLInputElement | null\nconst type = (input: HTMLInputElement, value: string) => {\n input.value = value\n input.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n}\n\ndescribe('the drawing size and unit (ADR-0144)', () => {\n it('a drawing with a scale shows its real size and ceiling in its display unit', async () => {\n const el = await panel({ mmPerUnit: 10, displayUnit: 'm', heights: { ceiling: 3000 } })\n expect([field(el, 'drawing-width')!.value, field(el, 'drawing-depth')!.value, field(el, 'drawing-ceiling')!.value]).to.deep.equal(['60', '40', '3'])\n expect(el.shadowRoot!.querySelector('[scale-unknown]')).to.equal(null)\n })\n\n it('a real width typed sets the width in coordinates through the scale', async () => {\n const el = await panel({ mmPerUnit: 10, displayUnit: 'm' })\n setTimeout(() => type(field(el, 'drawing-width')!, '70'))\n const { detail } = await oneEvent(el, 'bounds-change')\n expect(detail).to.deep.equal({ width: 7000 })\n })\n\n it('a ceiling typed is kept as a real length, in mm', async () => {\n const el = await panel({ mmPerUnit: 10, displayUnit: 'm', heights: { floor: 0, ceiling: 3000 } })\n setTimeout(() => type(field(el, 'drawing-ceiling')!, '4.5'))\n const { detail } = await oneEvent(el, 'property-change')\n expect(detail).to.deep.equal({ heights: { floor: 0, ceiling: 4500 } })\n })\n\n it('a drawing whose scale is unknown says so, and the real length of its width sets the scale', async () => {\n const el = await panel({ displayUnit: 'm' })\n expect(el.shadowRoot!.querySelector('[scale-unknown]')).to.not.equal(null)\n expect(field(el, 'drawing-width')).to.equal(null)\n ;(el.shadowRoot!.querySelector('button[calibrate]') as HTMLButtonElement).click()\n await el.updateComplete\n setTimeout(() => type(field(el, 'calibrate-length')!, '60'))\n const { detail } = await oneEvent(el, 'property-change')\n expect(detail).to.deep.equal({ mmPerUnit: 10 })\n })\n})\n"]}
|