@operato/scene-gauge 7.3.9 → 7.3.19

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.
@@ -1,321 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- import { Component, ComponentNature, Donut, ValueHolder } from '@hatiolab/things-scene'
6
-
7
- import { PROPERTIES } from './gauge-properties'
8
-
9
- const NATURE: ComponentNature = {
10
- mutable: false,
11
- resizable: true,
12
- rotatable: true,
13
- properties: [
14
- ...PROPERTIES,
15
- {
16
- type: 'number',
17
- label: 'start-angle',
18
- name: 'startAngle',
19
- property: 'startAngle'
20
- },
21
- {
22
- type: 'number',
23
- label: 'end-angle',
24
- name: 'endAngle',
25
- property: 'endAngle'
26
- },
27
- {
28
- type: 'color',
29
- label: 'text-fill-style',
30
- name: 'textFillStyle',
31
- property: 'textFillStyle'
32
- },
33
- {
34
- type: 'color',
35
- label: 'needle-fill-style',
36
- name: 'needleFillStyle',
37
- property: 'needleFillStyle'
38
- },
39
- {
40
- type: 'color',
41
- label: 'inner-circle-fill-style',
42
- name: 'innerCircleFillStyle',
43
- property: 'innerCircleFillStyle'
44
- },
45
- {
46
- type: 'checkbox',
47
- label: 'in-text',
48
- name: 'inText',
49
- property: 'inText'
50
- }
51
- ],
52
- help: 'scene/component/gauge-circle'
53
- }
54
-
55
- function countSignificantFigures(number: number) {
56
- const numStr = number.toString()
57
- const parts = numStr.split('.')
58
-
59
- // 소수점 이하 부분을 분석
60
- if (parts.length === 2) {
61
- const decimalPart = parts[1]
62
- let significantFigures = 0
63
-
64
- for (let i = 0; i < decimalPart.length; i++) {
65
- if (decimalPart[i] !== '0') {
66
- significantFigures = decimalPart.length - i
67
- break
68
- }
69
- }
70
-
71
- return significantFigures
72
- }
73
-
74
- // 정수인 경우 유효 자릿수 없음
75
- return 0
76
- }
77
-
78
- function drawStepLine(context: CanvasRenderingContext2D, ang: number, rx: number, stepNeedleSize: number) {
79
- context.rotate(ang)
80
- context.translate(0, -rx)
81
-
82
- context.fillRect(0, -rx * 0.14, stepNeedleSize, rx * 0.175)
83
- context.translate(0, rx)
84
- context.rotate(-ang)
85
- }
86
-
87
- function drawSubStepLine(context: CanvasRenderingContext2D, ang: number, rx: number, stepNeedleSize: number) {
88
- context.rotate(ang)
89
- context.translate(0, -rx)
90
-
91
- context.fillRect(0, -rx * 0.04, stepNeedleSize, rx * 0.075)
92
- context.translate(0, rx)
93
- context.rotate(-ang)
94
- }
95
-
96
- function drawStepText(context: CanvasRenderingContext2D, text: string, ang: number, rx: number) {
97
- context.rotate(ang)
98
- context.translate(0, -rx * 0.83)
99
- context.rotate(-ang)
100
-
101
- context.fillText(text, 0, 0)
102
- context.rotate(ang)
103
- context.translate(0, rx * 0.83)
104
- context.rotate(-ang)
105
- }
106
-
107
- function drawNeedle(context: CanvasRenderingContext2D, rx: number, ang: number) {
108
- context.rotate(ang)
109
-
110
- context.beginPath()
111
-
112
- context.moveTo(rx * 0.035, 0) // 중앙 두께
113
-
114
- context.lineTo(0, rx * 0.8) // 끝 점
115
-
116
- context.lineTo(-rx * 0.035, 0) // 중앙 두께
117
-
118
- context.lineTo(-rx * 0.015, -rx * 0.2) // 뒷쪽 두께
119
- context.lineTo(rx * 0.015, -rx * 0.2) // 뒷쪽 두께
120
-
121
- context.rotate(-ang)
122
- }
123
-
124
- export default class GaugeCircle extends ValueHolder(Donut) {
125
- render(context: CanvasRenderingContext2D) {
126
- var {
127
- lineWidth = 20,
128
- startValue,
129
- endValue,
130
- step,
131
- subStep,
132
- startAngle = 0,
133
- endAngle = 180,
134
- fontColor = 'black',
135
- showStepText = true,
136
- showStartValue = true,
137
- showEndValue = true,
138
- showStepLine = true,
139
- showSubStep = true,
140
- inText = true,
141
- colorStops, // 스텝별 각각 다른 색
142
- fillStyle,
143
- textFillStyle = 'black',
144
- needleFillStyle = 'black',
145
- innerCircleFillStyle = 'gray',
146
- stepNeedleSize = 2,
147
- stepFillStyle,
148
- stepTextSize,
149
- cx,
150
- cy,
151
- rx,
152
- ry,
153
- ratio,
154
- animFromBase = false
155
- } = this.state
156
-
157
- startValue = Number(startValue)
158
-
159
- this.animOnValueChange(this.value, animFromBase, startValue)
160
-
161
- const RADIAN = 0.0174533 / Math.PI
162
- const rxRatio = (rx / 100) * ratio // 원 안에 지워지는 비율을 계산한 rx - ratio의 비율에 따라 크기가 변함
163
- const ryRatio = (ry / 100) * ratio // 원 안에 지워지는 비율을 계산한 ry - ratio의 비율에 따라 크기가 변함
164
- const circleSize = (endAngle - startAngle) / 180 // 원의 총 길이. - PI * 2가 원이므로 (360도 = 2, 180도 = 1)
165
- const totalValue = endValue - startValue // 게이지의 시작과 끝 값의 크기
166
-
167
- startAngle = startAngle * RADIAN - 0.5 // 맨 위쪽을 중심으로 앵글의 범위에 따라 왼쪽으로 넓어짐
168
- endAngle = endAngle * RADIAN - 0.5 // 맨 위쪽을 중심으로 앵글의 범위에 따라 오른쪽으로 넓어짐
169
-
170
- context.translate(cx, cy)
171
-
172
- //// 메인 게이지 원 그리기 ////
173
- context.beginPath()
174
-
175
- context.ellipse(0, 0, Math.abs(rx), Math.abs(ry), 0, startAngle * Math.PI, endAngle * Math.PI)
176
- this.drawStroke(context)
177
- context.ellipse(0, 0, Math.abs(rxRatio), Math.abs(ryRatio), 0, endAngle * Math.PI, startAngle * Math.PI, true) // 반대로 그리며 원을 지움.
178
- // this.drawFill(context)
179
-
180
- context.closePath()
181
-
182
- //// 스텝별 색 칠하기 ////
183
- if (colorStops) {
184
- let beforeValue = 0
185
- let endStepAngle = 0
186
- context.moveTo(0, 0)
187
-
188
- colorStops.forEach(function (
189
- v: { position: number; color: string },
190
- idx: number,
191
- arr: { position: number; color: string }[]
192
- ) {
193
- context.beginPath()
194
-
195
- let value = Math.max(Math.min(v.position - startValue, totalValue), 0) // v.position 범위의 최소값은 0, 최대값은 totalValue가 되야함.
196
- let startStepAngle = endStepAngle || Math.PI * (startAngle + (circleSize * beforeValue) / totalValue)
197
-
198
- if (idx === arr.length - 1)
199
- // 마지막값은 무조건 끝까지 채워주도록 한다
200
- endStepAngle = Math.PI * (startAngle + circleSize)
201
- else endStepAngle = Math.PI * (startAngle + (circleSize * value) / totalValue)
202
-
203
- if (beforeValue > totalValue || beforeValue > value)
204
- // 값이 게이지의 최대 값을 넘어가거나 이전 값 보다 현재값이 작으면 다시 그릴 필요 없음
205
- return false
206
-
207
- context.ellipse(0, 0, Math.abs(rx), Math.abs(ry), 0, startStepAngle, endStepAngle)
208
- context.ellipse(0, 0, Math.abs(rxRatio), Math.abs(ryRatio), 0, endStepAngle, startStepAngle, true)
209
- context.fillStyle = v.color
210
- context.fill()
211
-
212
- beforeValue = value
213
- })
214
- }
215
- context.scale(1, ry / rx)
216
-
217
- //// 바늘 그리기 ////
218
- context.beginPath()
219
- let drawingValue = this.animValue
220
- drawingValue = Math.max(Math.min(drawingValue, endValue), startValue) // 그려지는 값은 startValue보다 작을 수 없고, endValue보다 클 수 없음.
221
-
222
- let ang = Math.PI * ((circleSize * (drawingValue - startValue)) / totalValue + startAngle - 0.5)
223
-
224
- drawNeedle(context, rx, ang)
225
-
226
- context.fillStyle = needleFillStyle
227
- context.fill()
228
-
229
- //// 중앙 원 그리기 ////
230
- context.beginPath()
231
- context.ellipse(0, 0, Math.abs(rx) / 15, Math.abs(rx) / 15, 0, 0, 2 * Math.PI)
232
- context.fillStyle = innerCircleFillStyle
233
- context.fill()
234
-
235
- //// 스텝 선 그리기 ////
236
- context.fillStyle = stepFillStyle
237
- if (showStepLine) {
238
- let count = totalValue / step
239
-
240
- // Draw StartValue
241
- drawStepLine(context, Math.PI * (startAngle + 0.5), rx * 0.8, stepNeedleSize) // 원을 그릴때 PI는 45도 부터 그리지만 angle은 0도부터 틀어서 + 0.5도를 곱해줘야함
242
- // Draw StepValue
243
- for (let num = 1; num < count; num++) {
244
- let ang = Math.PI * ((circleSize / count) * num + startAngle + 0.5)
245
-
246
- drawStepLine(context, ang, rx * 0.8, stepNeedleSize)
247
- }
248
- // Draw EndValue
249
- drawStepLine(context, Math.PI * (endAngle + 0.5), rx * 0.8, stepNeedleSize)
250
- }
251
-
252
- //// 서브 스탭 그리기 ////
253
- if (showSubStep && subStep > 0) {
254
- let count = Math.round(totalValue / subStep)
255
-
256
- // Draw StepValue
257
- for (let num = 1; num <= count; num++) {
258
- if ((num * subStep) % step == 0) {
259
- // 메인 스탭과 서브 스탭은 그리지 않음
260
- continue
261
- }
262
- let ang = Math.PI * ((circleSize / count) * num + startAngle + 0.5)
263
-
264
- drawSubStepLine(context, ang, rx * 0.8, stepNeedleSize)
265
- }
266
- }
267
-
268
- //// 스텝 텍스트 그리기 ////
269
- context.fillStyle = textFillStyle
270
- context.font = (rx * stepTextSize) / 50 + 'px arial'
271
- context.textBaseline = 'middle'
272
- context.textAlign = 'center'
273
- let textLocation = inText ? 0.8 : 1.35
274
-
275
- if (showStartValue) {
276
- // Draw StartText
277
- drawStepText(context, startValue, Math.PI * (startAngle + 0.5), rx * textLocation)
278
- }
279
-
280
- if (showEndValue) {
281
- // Draw EndText
282
- drawStepText(context, endValue, Math.PI * (endAngle + 0.5), rx * textLocation)
283
- }
284
-
285
- if (showStepText) {
286
- // Draw StepText
287
- let count = totalValue / step
288
- let significantFigures = countSignificantFigures(step)
289
-
290
- for (let num = 1; num < count; num++) {
291
- let value = startValue + step * num
292
- let ang = Math.PI * ((circleSize / count) * num + startAngle + 0.5)
293
-
294
- drawStepText(context, value.toFixed(significantFigures), ang, rx * textLocation)
295
- }
296
- }
297
-
298
- context.scale(1, rx / ry)
299
- context.translate(-cx, -cy)
300
- }
301
-
302
- contains(x: number, y: number): boolean {
303
- // 컨테인즈는 Ellipse로 정의함
304
- var { cx, cy, rx, ry } = this.state
305
-
306
- var normx = (x - cx) / (rx * 2 - 0.5)
307
- var normy = (y - cy) / (ry * 2 - 0.5)
308
-
309
- return normx * normx + normy * normy < 0.25
310
- }
311
-
312
- postrender(context: CanvasRenderingContext2D) {
313
- this.drawText(context)
314
- }
315
-
316
- get nature() {
317
- return NATURE
318
- }
319
- }
320
-
321
- Component.register('gauge-circle', GaugeCircle)
@@ -1,203 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- import { Component, ComponentNature, RectPath, Shape, ValueHolder } from '@hatiolab/things-scene'
6
-
7
- import { PROPERTIES } from './gauge-properties'
8
-
9
- const NATURE: ComponentNature = {
10
- mutable: false,
11
- resizable: true,
12
- rotatable: true,
13
- properties: [
14
- ...PROPERTIES,
15
- {
16
- type: 'color',
17
- label: 'text-fill-style',
18
- name: 'textFillStyle',
19
- property: 'textFillStyle'
20
- },
21
- {
22
- type: 'color',
23
- label: 'needle-fill-style',
24
- name: 'needleFillStyle',
25
- property: 'needleFillStyle'
26
- },
27
- {
28
- type: 'number',
29
- label: 'needle-size',
30
- name: 'needleSize',
31
- property: 'needleSize'
32
- }
33
- ],
34
- help: 'scene/component/gauge-horizon'
35
- }
36
-
37
- export default class GaugeHorizon extends ValueHolder(RectPath(Shape)) {
38
- render(context: CanvasRenderingContext2D) {
39
- var {
40
- startValue,
41
- endValue,
42
- step,
43
- subStep,
44
- colorStops,
45
- needleFillStyle,
46
- stepFillStyle,
47
- textFillStyle,
48
- needleSize,
49
- stepNeedleSize,
50
- stepTextSize,
51
- showStepText = true,
52
- showStartValue = true,
53
- showEndValue = true,
54
- showStepLine = true,
55
- showSubStep = true,
56
- width,
57
- height,
58
- top,
59
- left,
60
- animFromBase = false
61
- } = this.state
62
-
63
- startValue = Number(startValue)
64
-
65
- this.animOnValueChange(this.value, animFromBase, startValue)
66
-
67
- const totalValue = endValue - startValue // 게이지의 시작과 끝 값의 크기
68
-
69
- context.translate(left, top) // top과 left의 좌표에 영향을 받지 않기 위해 transalate를 한다음 모든 탑과 레프트의 좌표를 0으로 줌
70
-
71
- //// 메인 막대 그리기 ////
72
- context.beginPath()
73
-
74
- context.rect(0, 0, width, height)
75
-
76
- this.drawFill(context)
77
- this.drawStroke(context)
78
- context.closePath()
79
-
80
- //// 스텝별 색 칠하기 ////
81
- if (colorStops) {
82
- let beforeValue = 0
83
- colorStops.forEach(function (
84
- v: { position: number; color: string },
85
- idx: number,
86
- arr: { position: number; color: string }[]
87
- ) {
88
- context.beginPath()
89
-
90
- let value = Math.max(Math.min(v.position - startValue, totalValue), 0) // v.position 범위의 최소값은 0, 최대값은 totalValue가 되야함.
91
- let startStepPosition = (width * beforeValue) / totalValue
92
- let endStepPosition
93
- // console.log(startStepPosition + (width * value / totalValue));
94
- if (idx == arr.length - 1 || startStepPosition + (width * value) / totalValue)
95
- // 배열의 마지막 값이거나 중간 시작값 + 그려지는 값이 width 를 넘을 경우는 무조건 끝까지 채워주도록 한다
96
- endStepPosition = width - startStepPosition
97
- else endStepPosition = (width * value) / totalValue
98
-
99
- if (beforeValue > totalValue || beforeValue > value)
100
- // 값이 게이지의 최대 값을 넘어가거나 이전 값 보다 현재값이 작으면 다시 그릴 필요 없음
101
- return false
102
-
103
- context.rect(startStepPosition, 0, endStepPosition, height)
104
-
105
- context.fillStyle = v.color
106
- context.fill()
107
-
108
- beforeValue = value
109
- })
110
- }
111
-
112
- //// 스텝 선 그리기 ////
113
- context.fillStyle = stepFillStyle
114
- if (showStepLine) {
115
- let count = totalValue / step
116
- let stepSize = width * 0.06
117
-
118
- // Draw StartValue
119
- context.fillRect(0, height - stepSize, stepNeedleSize, stepSize)
120
- // Draw StepValue
121
- for (let num = 1; num < count; num++) {
122
- let locate = (width / count) * num
123
-
124
- context.fillRect(locate, height - stepSize, stepNeedleSize, stepSize)
125
- }
126
- // Draw EndValue
127
- context.fillRect(width, height - stepSize, stepNeedleSize, stepSize)
128
- }
129
-
130
- //// 서브 스탭 그리기 ////
131
- if (showSubStep) {
132
- let count = totalValue
133
- let subStepSize = width * 0.027
134
- // Draw StartValue
135
- context.fillRect(0, height - subStepSize, stepNeedleSize, subStepSize)
136
-
137
- // Draw StepValue
138
- for (let num = 1; num <= count; num++) {
139
- if (num % step == 0 || num % subStep != 0) {
140
- // 메인 스탭과 서브 스탭은 그리지 않음
141
- continue
142
- }
143
- let locate = (width / count) * num
144
- context.fillRect(locate, height - subStepSize, stepNeedleSize, subStepSize)
145
- }
146
- }
147
-
148
- //// 스텝 텍스트 그리기 ////
149
- let fontSize = (width * stepTextSize) / 150
150
- context.fillStyle = textFillStyle
151
- context.font = fontSize + 'px arial'
152
- context.textBaseline = 'middle'
153
- context.textAlign = 'center'
154
- if (showStartValue) {
155
- // Draw StartText
156
- context.fillText(startValue, 0, height + fontSize * 0.75)
157
- }
158
-
159
- if (showEndValue) {
160
- // Draw EndText
161
- context.fillText(endValue, width, height + fontSize * 0.75)
162
- }
163
-
164
- if (showStepText) {
165
- // Draw StepText
166
- let count = totalValue / step
167
-
168
- for (let num = 1; num < count; num++) {
169
- let value = startValue + step * num
170
- let locate = (width / count) * num
171
-
172
- context.fillText(value, locate, height + fontSize * 0.75)
173
- }
174
- }
175
-
176
- //// 바늘 그리기 ////
177
- context.beginPath()
178
- let drawingValue = this.animValue
179
- drawingValue = Math.max(Math.min(drawingValue, endValue), startValue) // 그려지는 값은 startValue보다 작을 수 없고, endValue보다 클 수 없음.
180
- let position = ((drawingValue - startValue) / totalValue) * width
181
-
182
- needleSize *= 4
183
- context.moveTo(position, height + fontSize * 1.4)
184
- context.lineTo(position + needleSize / 2, height + needleSize + fontSize * 1.4)
185
- context.lineTo(position - needleSize / 2, height + needleSize + fontSize * 1.4)
186
-
187
- context.fillStyle = needleFillStyle
188
- context.fill()
189
- context.closePath()
190
-
191
- context.translate(-left, -top)
192
- }
193
-
194
- postrender(context: CanvasRenderingContext2D) {
195
- this.drawText(context)
196
- }
197
-
198
- get nature() {
199
- return NATURE
200
- }
201
- }
202
-
203
- Component.register('gauge-horizon', GaugeHorizon)
@@ -1,114 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- export const PROPERTIES = [
6
- {
7
- type: 'string',
8
- label: 'value',
9
- name: 'value',
10
- property: 'value'
11
- },
12
- {
13
- type: 'number',
14
- label: 'start-value',
15
- name: 'startValue',
16
- observe: function (this: HTMLElement, startValue: number) {
17
- const colorStops: any = this.parentNode!.querySelector('[name=colorStops]')
18
- colorStops.property.min = startValue
19
- },
20
- property: 'startValue'
21
- },
22
- {
23
- type: 'number',
24
- label: 'end-value',
25
- name: 'endValue',
26
- observe: function (this: HTMLElement, endValue: number) {
27
- const colorStops: any = this.parentNode!.querySelector('[name=colorStops]')
28
- colorStops.property.max = endValue
29
- },
30
- property: 'endValue'
31
- },
32
- {
33
- type: 'number',
34
- label: 'step',
35
- name: 'step',
36
- property: 'step'
37
- },
38
- {
39
- type: 'number',
40
- label: 'step-text-size',
41
- name: 'stepTextSize',
42
- property: 'stepTextSize'
43
- },
44
- {
45
- type: 'number',
46
- label: 'sub-step',
47
- name: 'subStep',
48
- property: 'subStep'
49
- },
50
- {
51
- type: 'number',
52
- label: 'step-needle-size',
53
- name: 'stepNeedleSize',
54
- property: 'stepNeedleSize'
55
- },
56
- {
57
- type: 'color',
58
- label: 'step-fill-style',
59
- name: 'stepFillStyle',
60
- property: 'stepFillStyle'
61
- },
62
- {
63
- type: 'solid-color-stops',
64
- label: 'color-stops',
65
- name: 'colorStops',
66
- property: {
67
- min: 0,
68
- max: 100
69
- }
70
- },
71
- {
72
- type: 'legend',
73
- label: '',
74
- name: 'toggleOption',
75
- property: {
76
- label: 'Toggle Option'
77
- }
78
- },
79
- {
80
- type: 'checkbox',
81
- label: 'show-start-value',
82
- name: 'showStartValue',
83
- property: 'showStartValue'
84
- },
85
- {
86
- type: 'checkbox',
87
- label: 'show-end-value',
88
- name: 'showEndValue',
89
- property: 'showEndValue'
90
- },
91
- {
92
- type: 'checkbox',
93
- label: 'show-step-line',
94
- name: 'showStepLine',
95
- property: 'showStepLine'
96
- },
97
- {
98
- type: 'checkbox',
99
- label: 'show-step-text',
100
- name: 'showStepText',
101
- property: 'showStepText'
102
- },
103
- {
104
- type: 'checkbox',
105
- label: 'show-sub-step',
106
- name: 'showSubStep',
107
- property: 'showSubStep'
108
- },
109
- {
110
- type: 'checkbox',
111
- label: 'anim-from-base',
112
- name: 'animFromBase'
113
- }
114
- ]