@fmsim/machine 2.0.0-beta.99 → 2.0.1

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 (73) hide show
  1. package/dist/carrier-manager.js +9 -1
  2. package/dist/carrier-manager.js.map +1 -1
  3. package/dist/carrier.js +69 -52
  4. package/dist/carrier.js.map +1 -1
  5. package/dist/crane.js +15 -6
  6. package/dist/crane.js.map +1 -1
  7. package/dist/factories/agv-3d.js +9 -27
  8. package/dist/factories/agv-3d.js.map +1 -1
  9. package/dist/factories/conveyor-3d.js +11 -19
  10. package/dist/factories/conveyor-3d.js.map +1 -1
  11. package/dist/factories/crane-3d.js +8 -17
  12. package/dist/factories/crane-3d.js.map +1 -1
  13. package/dist/factories/crane-rail-3d.js +8 -12
  14. package/dist/factories/crane-rail-3d.js.map +1 -1
  15. package/dist/factories/machine-3d.js +100 -63
  16. package/dist/factories/machine-3d.js.map +1 -1
  17. package/dist/factories/oht-3d.js +9 -27
  18. package/dist/factories/oht-3d.js.map +1 -1
  19. package/dist/factories/shuttle-3d.js +11 -27
  20. package/dist/factories/shuttle-3d.js.map +1 -1
  21. package/dist/features/capacity-gauge-mixin.js +520 -0
  22. package/dist/features/capacity-gauge-mixin.js.map +1 -0
  23. package/dist/features/mcs-status-default.js +13 -0
  24. package/dist/features/mcs-status-default.js.map +1 -1
  25. package/dist/features/parent-object-mixin.js +5 -1
  26. package/dist/features/parent-object-mixin.js.map +1 -1
  27. package/dist/mcs-machine.js +4 -23
  28. package/dist/mcs-machine.js.map +1 -1
  29. package/dist/mcs-unit.js +2 -5
  30. package/dist/mcs-unit.js.map +1 -1
  31. package/dist/mcs-vehicle.js +3 -1
  32. package/dist/mcs-vehicle.js.map +1 -1
  33. package/dist/scene/root-container-override.js +5 -2
  34. package/dist/scene/root-container-override.js.map +1 -1
  35. package/dist/stocker-capacity-bar.js +11 -372
  36. package/dist/stocker-capacity-bar.js.map +1 -1
  37. package/dist/stocker.js +29 -1
  38. package/dist/stocker.js.map +1 -1
  39. package/dist/tsconfig.tsbuildinfo +1 -1
  40. package/dist/utils/crane-position.js +23 -14
  41. package/dist/utils/crane-position.js.map +1 -1
  42. package/dist/utils/stocker-gauge.js +48 -10
  43. package/dist/utils/stocker-gauge.js.map +1 -1
  44. package/dist/zone-capacity-bar.js +13 -213
  45. package/dist/zone-capacity-bar.js.map +1 -1
  46. package/package.json +4 -4
  47. package/src/carrier-manager.ts +9 -1
  48. package/src/carrier.ts +73 -52
  49. package/src/crane.ts +14 -5
  50. package/src/factories/agv-3d.ts +10 -26
  51. package/src/factories/conveyor-3d.ts +12 -19
  52. package/src/factories/crane-3d.ts +9 -17
  53. package/src/factories/crane-rail-3d.ts +9 -13
  54. package/src/factories/machine-3d.ts +125 -66
  55. package/src/factories/oht-3d.ts +10 -26
  56. package/src/factories/shuttle-3d.ts +12 -26
  57. package/src/features/capacity-gauge-mixin.ts +642 -0
  58. package/src/features/mcs-status-default.ts +13 -0
  59. package/src/features/parent-object-mixin.ts +5 -1
  60. package/src/mcs-machine.ts +4 -23
  61. package/src/mcs-unit.ts +2 -5
  62. package/src/mcs-vehicle.ts +3 -1
  63. package/src/scene/root-container-override.ts +5 -2
  64. package/src/stocker-capacity-bar.ts +15 -476
  65. package/src/stocker.ts +29 -1
  66. package/src/utils/crane-position.ts +46 -14
  67. package/src/utils/stocker-gauge.ts +63 -10
  68. package/src/zone-capacity-bar.ts +17 -282
  69. package/translations/en.json +4 -1
  70. package/translations/ja.json +4 -1
  71. package/translations/ko.json +4 -1
  72. package/translations/ms.json +4 -1
  73. package/translations/zh.json +4 -1
@@ -10,7 +10,8 @@
10
10
  * }
11
11
  *
12
12
  * current 를 limit 범위 안의 0~1 비율로 환산한 뒤 host(부모) footprint 에 매핑한다.
13
- * x → host 긴쪽, y → 짧은쪽, z → 포크 높이(forkZ 0~100).
13
+ * z → 포크 높이(forkZ 0~100). x/y 의 축 배정과 원점은 host 좌표계 설정(CoordMapping)을
14
+ * 따르고, 미설정 시 x → host 긴쪽, y → 짧은쪽, 원점 = 좌상단.
14
15
  */
15
16
 
16
17
  import { parseIfJsonString } from './data-value'
@@ -39,6 +40,26 @@ export function axisRatio(value: unknown, lim?: AxisLimit): number {
39
40
  return Math.max(0, Math.min(1, (v - min) / (max - min)))
40
41
  }
41
42
 
43
+ /**
44
+ * host(보통 STOCKER) 의 **내부 좌표계** 설정 — host state 에서 읽는다.
45
+ *
46
+ * 외부 시스템이 보내는 좌표의 X/Y 를 host footprint 의 어느 축·어느 방향에 대응시킬지
47
+ * 정한다. 크레인 전용이 아니라 host 자신의 좌표 규약이므로, 같은 좌표계를 쓰는 다른
48
+ * 자식(Shelf 등)도 동일하게 참조할 수 있다. 모두 미설정이면 종전 동작(긴쪽=X,
49
+ * 원점=left/top)과 같다.
50
+ *
51
+ * 주의: **로컬 프레임 기준**이다. host 회전(rotation)은 렌더 단계에서 적용되므로,
52
+ * 이 설정은 회전 전 모델 좌표계로 이해해야 한다.
53
+ */
54
+ export type CoordMapping = {
55
+ /** 내부 X 가 달리는 축. 'auto'(기본) = 긴 변. */
56
+ axisX?: 'auto' | 'width' | 'height'
57
+ /** X=0 을 반대쪽 끝으로. */
58
+ invertX?: boolean
59
+ /** Y=0 을 반대쪽 끝으로. */
60
+ invertY?: boolean
61
+ }
62
+
42
63
  /**
43
64
  * host(부모) footprint 안에서 0~1 비율 (rx,ry) → 크레인 top-left 로컬 좌표.
44
65
  *
@@ -47,7 +68,8 @@ export function axisRatio(value: unknown, lim?: AxisLimit): number {
47
68
  * craneLen/2 만큼 inset 된 중심선 위를 움직임). 크레인이 host 보다 크면 span 0
48
69
  * 으로 떨어져 host 모서리에 정렬.
49
70
  *
50
- * x(rx) 는 host 의 긴쪽, y(ry) 는 짧은쪽에 매핑 (가상 rail 은 host 긴쪽 방향).
71
+ * 축 배정과 원점은 opts(CoordMapping = host 의 내부 좌표계 설정)로 정한다. 기본(미설정)은
72
+ * x(rx) → host 의 긴쪽, y(ry) → 짧은쪽, 원점 = left/top.
51
73
  */
52
74
  export function mapCraneLocalPosition(
53
75
  hostW: number,
@@ -55,24 +77,34 @@ export function mapCraneLocalPosition(
55
77
  craneW: number,
56
78
  craneH: number,
57
79
  rx: number,
58
- ry: number
80
+ ry: number,
81
+ opts: CoordMapping = {}
59
82
  ): { left: number; top: number } {
60
- const longIsWidth = hostW >= hostH
61
- const longLen = longIsWidth ? hostW : hostH
62
- const shortLen = longIsWidth ? hostH : hostW
63
- const craneLongSize = longIsWidth ? craneW : craneH
64
- const craneShortSize = longIsWidth ? craneH : craneW
83
+ // 내부 X 가 달리는 축 배정: 명시 설정 우선, 'auto'/미설정은 긴 변(종전 폴백).
84
+ // 정사각형에 가까운 host 는 auto 가 리사이즈로 뒤집힐 수 있어 명시 지정을 권한다.
85
+ const xIsWidth = opts.axisX === 'width' ? true : opts.axisX === 'height' ? false : hostW >= hostH
86
+
87
+ // 반전은 *비율 단계*에서 흡수 — pos = (1-r)*span 이 위치 뒤집기와 동일하고 더 단순하다.
88
+ const fx = opts.invertX ? 1 - rx : rx
89
+ const fy = opts.invertY ? 1 - ry : ry
90
+
91
+ // 데이터 X/Y 축 기준으로 길이를 잡는다. axisX 를 명시하면 X 가 짧은 변일 수도 있으므로
92
+ // 길이(long/short)가 아니라 축 이름으로 부른다.
93
+ const xLen = xIsWidth ? hostW : hostH
94
+ const yLen = xIsWidth ? hostH : hostW
95
+ const craneXSize = xIsWidth ? craneW : craneH
96
+ const craneYSize = xIsWidth ? craneH : craneW
65
97
 
66
98
  // 크레인 크기를 뺀 inset 가용 span. top-left = ratio * span 이므로 크레인
67
99
  // 전체가 host [0, hostLen] 안에 들어온다.
68
- const longSpan = Math.max(0, longLen - craneLongSize)
69
- const shortSpan = Math.max(0, shortLen - craneShortSize)
70
- const longPos = rx * longSpan
71
- const shortPos = ry * shortSpan
100
+ const xSpan = Math.max(0, xLen - craneXSize)
101
+ const ySpan = Math.max(0, yLen - craneYSize)
102
+ const xPos = fx * xSpan
103
+ const yPos = fy * ySpan
72
104
 
73
105
  return {
74
- left: longIsWidth ? longPos : shortPos,
75
- top: longIsWidth ? shortPos : longPos
106
+ left: xIsWidth ? xPos : yPos,
107
+ top: xIsWidth ? yPos : xPos
76
108
  }
77
109
  }
78
110
 
@@ -11,9 +11,13 @@
11
11
  * - abnormal : CARRIER_NORMAL / CARRIER_ABNORMAL
12
12
  */
13
13
 
14
+ import { Legend } from '../features/mcs-status-default'
15
+
14
16
  export type StockerGaugeMode = 'capacity' | 'carrier' | 'abnormal'
15
17
 
16
18
  export interface GaugeSegment {
19
+ /** 안정적 식별 토큰 (대문자, 클릭 이벤트 payload·데이터 필드 관례와 일치). */
20
+ key: 'FULL' | 'EMPTY' | 'EMPTYEMPTY' | 'NORMAL' | 'ABNORMAL'
17
21
  /** 세그먼트 라벨(2D per-segment 표시용, '\n' 은 줄바꿈). */
18
22
  label: string
19
23
  /** 카운트 원본값. */
@@ -24,13 +28,33 @@ export interface GaugeSegment {
24
28
  color: string
25
29
  }
26
30
 
27
- /** carrier 세그먼트 색상 (2D/3D 공통). */
31
+ /** carrier 세그먼트 색상 (2D/3D 공통). LEGEND_CARRIER 기본값과 동일 — 테마 미지정 시 폴백. */
28
32
  export const CARRIER_COLORS = {
29
33
  full: '#4AA7FE',
30
34
  empty: '#8BDA5B',
31
35
  emptyEmpty: '#019D59'
32
36
  }
33
37
 
38
+ export interface CarrierColors {
39
+ full: string
40
+ empty: string
41
+ emptyEmpty: string
42
+ }
43
+
44
+ /**
45
+ * carrier legend(테마)에서 full/empty/emptyEmpty 색상 추출.
46
+ * carrier 컴포넌트의 색 취득 로직(statusColor = legend[status] || legend.default)과 동일하게,
47
+ * status 키(FULL/EMPTY/EMPTYEMPTY)로 직접 조회한다. 키/default 모두 없으면 CARRIER_COLORS 로 폴백.
48
+ */
49
+ export function carrierColorsFromLegend(legend?: Legend): CarrierColors {
50
+ const pick = (key: string, fallback: string) => (legend && (legend[key] || legend.default)) || fallback
51
+ return {
52
+ full: pick('FULL', CARRIER_COLORS.full),
53
+ empty: pick('EMPTY', CARRIER_COLORS.empty),
54
+ emptyEmpty: pick('EMPTYEMPTY', CARRIER_COLORS.emptyEmpty)
55
+ }
56
+ }
57
+
34
58
  /** abnormal 세그먼트 색상 (2D/3D 공통). */
35
59
  export const ABNORMAL_COLORS = {
36
60
  normal: '#8BDA5B',
@@ -42,17 +66,25 @@ function num(v: unknown): number {
42
66
  return Number.isFinite(n) && n > 0 ? n : 0
43
67
  }
44
68
 
45
- /** 캐리어 상태 세그먼트 (Full / Empty / EmptyEmpty). total 0 이면 모든 ratio 0. */
46
- export function carrierSegments(full: unknown, empty: unknown, emptyEmpty: unknown): GaugeSegment[] {
69
+ /**
70
+ * 캐리어 상태 세그먼트 (Full / Empty / EmptyEmpty). total 0 이면 모든 ratio 0.
71
+ * colors 미지정 시 CARRIER_COLORS(기본). 테마 색은 carrierColorsFromLegend 로 만들어 전달.
72
+ */
73
+ export function carrierSegments(
74
+ full: unknown,
75
+ empty: unknown,
76
+ emptyEmpty: unknown,
77
+ colors: CarrierColors = CARRIER_COLORS
78
+ ): GaugeSegment[] {
47
79
  const f = num(full)
48
80
  const e = num(empty)
49
81
  const ee = num(emptyEmpty)
50
82
  const total = f + e + ee
51
83
  const r = (c: number) => (total > 0 ? c / total : 0)
52
84
  return [
53
- { label: 'Full', count: f, ratio: r(f), color: CARRIER_COLORS.full },
54
- { label: 'Empty', count: e, ratio: r(e), color: CARRIER_COLORS.empty },
55
- { label: 'Empty\nEmpty', count: ee, ratio: r(ee), color: CARRIER_COLORS.emptyEmpty }
85
+ { key: 'FULL', label: 'Full', count: f, ratio: r(f), color: colors.full },
86
+ { key: 'EMPTY', label: 'Empty', count: e, ratio: r(e), color: colors.empty },
87
+ { key: 'EMPTYEMPTY', label: 'Empty\nEmpty', count: ee, ratio: r(ee), color: colors.emptyEmpty }
56
88
  ]
57
89
  }
58
90
 
@@ -63,15 +95,36 @@ export function abnormalSegments(normal: unknown, abnormal: unknown): GaugeSegme
63
95
  const total = n + a
64
96
  const r = (c: number) => (total > 0 ? c / total : 0)
65
97
  return [
66
- { label: 'Normal', count: n, ratio: r(n), color: ABNORMAL_COLORS.normal },
67
- { label: 'Abnormal', count: a, ratio: r(a), color: ABNORMAL_COLORS.abnormal }
98
+ { key: 'NORMAL', label: 'Normal', count: n, ratio: r(n), color: ABNORMAL_COLORS.normal },
99
+ { key: 'ABNORMAL', label: 'Abnormal', count: a, ratio: r(a), color: ABNORMAL_COLORS.abnormal }
68
100
  ]
69
101
  }
70
102
 
103
+ /**
104
+ * 누적 비율 위치(pos, 0..span 범위)가 속한 세그먼트를 반환한다. ratio 0 세그먼트는
105
+ * 화면에 없으므로 건너뛴다. 경계(pos == span)·초과 클릭은 마지막 비영 세그먼트로 귀속하고,
106
+ * 데이터가 전혀 없으면(모든 ratio 0) null.
107
+ *
108
+ * renderSegmentGauge 의 배치와 동일 규칙(누적 채움)이며, 2D 렌더와 클릭 판정이 이 함수를
109
+ * 공유해 drift 를 막는다. 방향(landscape 왼→오 / portrait 아래→위)은 호출부가 pos 로 흡수한다.
110
+ */
111
+ export function pickSegmentAt(segments: GaugeSegment[], pos: number, span: number): GaugeSegment | null {
112
+ let acc = 0
113
+ let lastNonZero: GaugeSegment | null = null
114
+ for (const seg of segments) {
115
+ const segLen = span * seg.ratio
116
+ if (segLen <= 0) continue
117
+ lastNonZero = seg
118
+ if (pos < acc + segLen) return seg
119
+ acc += segLen
120
+ }
121
+ return lastNonZero
122
+ }
123
+
71
124
  /** 캐리어 세그먼트 — canonical raw data(CARRIER_*) 에서 직접. 3D 처럼 raw data 소스용. */
72
- export function carrierSegmentsFromData(data: any): GaugeSegment[] {
125
+ export function carrierSegmentsFromData(data: any, colors?: CarrierColors): GaugeSegment[] {
73
126
  const d = data && typeof data === 'object' ? data : {}
74
- return carrierSegments(d.CARRIER_FULL, d.CARRIER_EMPTY, d.CARRIER_EMPTY_EMPTY)
127
+ return carrierSegments(d.CARRIER_FULL, d.CARRIER_EMPTY, d.CARRIER_EMPTY_EMPTY, colors)
75
128
  }
76
129
 
77
130
  /** 비정상 세그먼트 — canonical raw data(CARRIER_*) 에서 직접. */
@@ -1,301 +1,36 @@
1
- import { Component, ComponentNature, POSITION, Properties, sceneComponent } from '@hatiolab/things-scene'
2
- import { themesColorRange } from '@fmsim/api'
3
- import { LEGEND_CAPACITY } from './features/mcs-status-default'
4
- import { safeRound } from './utils/safe-round'
5
- import { getValueOnRanges } from './utils/get-value-on-ranges'
1
+ import { ComponentNature, sceneComponent } from '@hatiolab/things-scene'
2
+ import { LEGEND_CAPACITY, Legend } from './features/mcs-status-default'
6
3
  import { MCSZoneMixin, MCSZoneMixinProperties } from './features/mcs-zone-mixin'
7
4
  import { ParentObjectMixinProperties } from './features/parent-object-mixin'
5
+ import { CapacityGaugeMixin, CapacityGaugeMixinProperties } from './features/capacity-gauge-mixin'
8
6
  import MCSUnit from './mcs-unit'
9
7
 
8
+ /**
9
+ * 존(zone) 게이지.
10
+ *
11
+ * mode 에 따라 capacity / carrier / abnormal 3가지 게이지를 표현한다 — 그리는 규칙은
12
+ * StockerCapacityBar 와 동일하며 CapacityGaugeMixin 에서 공유한다(단일 소스).
13
+ * 스토커 게이지와 달리 존 게이지는 자체 id 로 데이터를 받는 Unit(identifiable) 이며,
14
+ * legend 폴백만 zone 전역 테마(zoneCapacityLegendTheme)로 다르다.
15
+ *
16
+ * mode 소스: root.stockerGaugeMode — 스토커 게이지와 같은 런타임 스위치로 함께 전환된다.
17
+ */
18
+
10
19
  const NATURE: ComponentNature = {
11
20
  mutable: false,
12
21
  resizable: true,
13
22
  rotatable: true,
14
- properties: [
15
- ...MCSZoneMixinProperties,
16
- ...ParentObjectMixinProperties,
17
- {
18
- type: 'select',
19
- label: 'legend-name',
20
- name: 'legendName',
21
- property: {
22
- options: themesColorRange
23
- }
24
- },
25
- {
26
- type: 'number',
27
- name: 'currentUsage',
28
- label: 'current-usage'
29
- },
30
- {
31
- type: 'number',
32
- name: 'highWatermark',
33
- label: 'high-watermark'
34
- },
35
- {
36
- type: 'number',
37
- name: 'lowWatermark',
38
- label: 'low-watermark'
39
- },
40
- {
41
- type: 'number',
42
- name: 'maxCapacity',
43
- label: 'max-capacity'
44
- },
45
- {
46
- type: 'boolean',
47
- name: 'fullup',
48
- label: 'fullup'
49
- },
50
- {
51
- type: 'number',
52
- label: 'round',
53
- name: 'round',
54
- property: {
55
- min: 0
56
- }
57
- },
58
- {
59
- type: 'hidden',
60
- name: 'usage',
61
- label: 'usage'
62
- }
63
- ],
23
+ properties: [...MCSZoneMixinProperties, ...ParentObjectMixinProperties, ...CapacityGaugeMixinProperties],
64
24
  'value-property': 'usage'
65
25
  }
66
26
 
67
- var controlHandler = {
68
- ondragmove: function (point: POSITION, index: number, component: Component) {
69
- var { left, top, width, height } = component.model
70
-
71
- var transcoorded = component.transcoordP2S(point.x, point.y)
72
- var round = ((transcoorded.x - left) / (width / 2)) * 100
73
-
74
- round = safeRound(round, width, height)
75
-
76
- component.set({
77
- round
78
- })
79
- }
80
- }
81
-
82
27
  @sceneComponent('ZoneCapacityBar')
83
- export default class ZoneCapacityBar extends MCSZoneMixin(MCSUnit) {
28
+ export default class ZoneCapacityBar extends CapacityGaugeMixin(MCSZoneMixin(MCSUnit)) {
84
29
  static get nature() {
85
30
  return NATURE
86
31
  }
87
32
 
88
- get controls() {
89
- var { left, top, width, round, height } = this.state
90
- round = round == undefined ? 0 : safeRound(round, width, height)
91
-
92
- return [
93
- {
94
- x: left + (width / 2) * (round / 100),
95
- y: top,
96
- handler: controlHandler
97
- }
98
- ]
99
- }
100
-
101
- getLegendFallback() {
33
+ getLegendFallback(): Legend {
102
34
  return (this.root as any).zoneCapacityLegendTheme || LEGEND_CAPACITY
103
35
  }
104
-
105
- get statusColor() {
106
- const { fullup } = this.state
107
- return fullup ? 'red' : getValueOnRanges(this.usage, this.legend)
108
- }
109
-
110
- get text() {
111
- return this.usage + '%'
112
- }
113
-
114
- render(context: CanvasRenderingContext2D) {
115
- const { left, top, width, height } = this.bounds
116
-
117
- if (width >= height) {
118
- this.renderLandscape(context)
119
- } else {
120
- this.renderPortrait(context)
121
- }
122
- }
123
-
124
- renderLandscape(context: CanvasRenderingContext2D) {
125
- const { left, top, width, height } = this.bounds
126
- const { highWatermark, lowWatermark, lineWidth, strokeStyle, round, fillStyle = 'white' } = this.state
127
-
128
- context.save()
129
- context.translate(left, top)
130
-
131
- // gauge background
132
- context.beginPath()
133
-
134
- context.fillStyle = fillStyle
135
- context.roundRect(0, 0, width, height, round)
136
-
137
- context.fill()
138
- context.stroke()
139
-
140
- context.clip()
141
-
142
- // gauge foreground
143
- context.beginPath()
144
-
145
- context.fillStyle = this.statusColor!
146
-
147
- context.rect(0, 0, (width / 100) * this.usage, height)
148
- context.fill()
149
-
150
- // high-watermark level
151
-
152
- if (highWatermark && highWatermark > 0 && highWatermark < 100) {
153
- context.beginPath()
154
-
155
- context.strokeStyle = 'black'
156
- context.lineWidth = 1
157
- context.setLineDash([3])
158
-
159
- const x = (width / 100) * highWatermark
160
- context.moveTo(x, 0)
161
- context.lineTo(x, height)
162
-
163
- context.stroke()
164
- }
165
-
166
- // low-watermark level
167
-
168
- if (lowWatermark && lowWatermark > 0 && lowWatermark < 100) {
169
- context.beginPath()
170
-
171
- context.strokeStyle = 'black'
172
- context.lineWidth = 1
173
- context.setLineDash([3])
174
-
175
- const x = (width / 100) * lowWatermark
176
- context.moveTo(x, 0)
177
- context.lineTo(x, height)
178
-
179
- context.stroke()
180
- }
181
-
182
- // gauge outline
183
- context.beginPath()
184
-
185
- context.setLineDash([])
186
- context.strokeStyle = strokeStyle
187
- context.lineWidth = lineWidth
188
- context.roundRect(0, 0, width, height, round)
189
- context.stroke()
190
-
191
- context.beginPath()
192
-
193
- context.translate(-left, -top)
194
- context.restore()
195
- }
196
-
197
- renderPortrait(context: CanvasRenderingContext2D) {
198
- const { left, top, width, height } = this.bounds
199
- const { highWatermark, lowWatermark, lineWidth, strokeStyle, round, fillStyle = 'white' } = this.state
200
-
201
- context.save()
202
- context.translate(left, top)
203
-
204
- // gauge background
205
- context.beginPath()
206
-
207
- context.fillStyle = fillStyle
208
- context.roundRect(0, 0, width, height, round)
209
-
210
- context.fill()
211
-
212
- context.clip()
213
-
214
- // gauge foreground
215
- context.beginPath()
216
-
217
- context.fillStyle = this.statusColor!
218
-
219
- context.rect(0, height - (height / 100) * this.usage, width, (height / 100) * this.usage)
220
- context.fill()
221
-
222
- // high-watermark level
223
-
224
- if (highWatermark && highWatermark > 0 && highWatermark < 100) {
225
- context.beginPath()
226
-
227
- context.strokeStyle = 'black'
228
- context.lineWidth = 1
229
- context.setLineDash([3])
230
-
231
- const y = height - (height / 100) * highWatermark
232
- context.moveTo(0, y)
233
- context.lineTo(width, y)
234
-
235
- context.stroke()
236
- }
237
-
238
- // low-watermark level
239
-
240
- if (lowWatermark && lowWatermark > 0 && lowWatermark < 100) {
241
- context.beginPath()
242
-
243
- context.strokeStyle = 'black'
244
- context.lineWidth = 1
245
- context.setLineDash([3])
246
-
247
- const y = height - (height / 100) * lowWatermark
248
- context.moveTo(0, y)
249
- context.lineTo(width, y)
250
-
251
- context.stroke()
252
- }
253
-
254
- // gauge outline
255
- context.beginPath()
256
-
257
- context.setLineDash([])
258
- context.strokeStyle = strokeStyle
259
- context.lineWidth = lineWidth
260
- context.roundRect(0, 0, width, height, round)
261
- context.stroke()
262
-
263
- context.beginPath()
264
-
265
- context.translate(-left, -top)
266
- context.restore()
267
- }
268
-
269
- get usage() {
270
- const { currentUsage = 0, maxCapacity = 100 } = this.state
271
- return Math.round((currentUsage / maxCapacity) * 100)
272
- }
273
-
274
- set usage(usage: number) {
275
- // intentionally have done nothing
276
- }
277
-
278
- onchangeData(after: Record<string, any>, before: Record<string, any>): void {
279
- const {
280
- CURRENTCAPACITY = 0,
281
- MAXCAPACITY = 100,
282
- HIGHWATERMARK = 100,
283
- LOWWATERMARK = 0,
284
- FULLUP = 'F'
285
- } = this.data && typeof this.data == 'object' ? this.data : {}
286
-
287
- const currentUsage = Number(CURRENTCAPACITY) || 0
288
- const maxCapacity = Number(MAXCAPACITY) || 100
289
- const highWatermark = Number(HIGHWATERMARK) || 100
290
- const lowWatermark = Number(LOWWATERMARK) || 0
291
-
292
- this.setState({
293
- currentUsage,
294
- maxCapacity,
295
- highWatermark,
296
- lowWatermark,
297
- fullup: FULLUP == 'T',
298
- usage: Math.round((currentUsage / maxCapacity) * 100)
299
- })
300
- }
301
36
  }
@@ -71,5 +71,8 @@
71
71
  "label.light-preset": "light preset",
72
72
  "label.dark": "dark",
73
73
  "label.medium": "medium",
74
- "label.bright": "bright"
74
+ "label.bright": "bright",
75
+ "label.coord-axis-x": "internal x axis",
76
+ "label.coord-invert-x": "invert x origin",
77
+ "label.coord-invert-y": "invert y origin"
75
78
  }
@@ -73,5 +73,8 @@
73
73
  "label.light-preset": "照明プリセット",
74
74
  "label.dark": "暗",
75
75
  "label.medium": "中",
76
- "label.bright": "明"
76
+ "label.bright": "明",
77
+ "label.coord-axis-x": "内部X軸",
78
+ "label.coord-invert-x": "X原点反転",
79
+ "label.coord-invert-y": "Y原点反転"
77
80
  }
@@ -74,5 +74,8 @@
74
74
  "label.light-preset": "조명 프리셋",
75
75
  "label.dark": "어두움",
76
76
  "label.medium": "중간",
77
- "label.bright": "밝음"
77
+ "label.bright": "밝음",
78
+ "label.coord-axis-x": "내부 X축",
79
+ "label.coord-invert-x": "X 원점 반전",
80
+ "label.coord-invert-y": "Y 원점 반전"
78
81
  }
@@ -73,5 +73,8 @@
73
73
  "label.light-preset": "pratetapan cahaya",
74
74
  "label.dark": "gelap",
75
75
  "label.medium": "sederhana",
76
- "label.bright": "cerah"
76
+ "label.bright": "cerah",
77
+ "label.coord-axis-x": "internal x axis",
78
+ "label.coord-invert-x": "invert x origin",
79
+ "label.coord-invert-y": "invert y origin"
77
80
  }
@@ -73,5 +73,8 @@
73
73
  "label.light-preset": "灯光预设",
74
74
  "label.dark": "昏暗",
75
75
  "label.medium": "适中",
76
- "label.bright": "明亮"
76
+ "label.bright": "明亮",
77
+ "label.coord-axis-x": "内部X轴",
78
+ "label.coord-invert-x": "X原点反转",
79
+ "label.coord-invert-y": "Y原点反转"
77
80
  }