@operato/scene-basic 1.2.5
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 +11 -0
- package/README.md +0 -0
- package/demo/index.html +158 -0
- package/demo/things-scene-basic.html +6 -0
- package/dist/anchors/ellipse-anchors.d.ts +7 -0
- package/dist/anchors/ellipse-anchors.js +43 -0
- package/dist/anchors/ellipse-anchors.js.map +1 -0
- package/dist/audio.d.ts +25 -0
- package/dist/audio.js +141 -0
- package/dist/audio.js.map +1 -0
- package/dist/cloud.d.ts +13 -0
- package/dist/cloud.js +30 -0
- package/dist/cloud.js.map +1 -0
- package/dist/donut.d.ts +15 -0
- package/dist/donut.js +74 -0
- package/dist/donut.js.map +1 -0
- package/dist/ellipse.d.ts +24 -0
- package/dist/ellipse.js +72 -0
- package/dist/ellipse.js.map +1 -0
- package/dist/gif-view.d.ts +18 -0
- package/dist/gif-view.js +116 -0
- package/dist/gif-view.js.map +1 -0
- package/dist/image-view.d.ts +19 -0
- package/dist/image-view.js +180 -0
- package/dist/image-view.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/outline/ellipse-outline.d.ts +2 -0
- package/dist/outline/ellipse-outline.js +11 -0
- package/dist/outline/ellipse-outline.js.map +1 -0
- package/dist/polygon.d.ts +19 -0
- package/dist/polygon.js +84 -0
- package/dist/polygon.js.map +1 -0
- package/dist/polyline.d.ts +18 -0
- package/dist/polyline.js +102 -0
- package/dist/polyline.js.map +1 -0
- package/dist/rect.d.ts +19 -0
- package/dist/rect.js +60 -0
- package/dist/rect.js.map +1 -0
- package/dist/star.d.ts +13 -0
- package/dist/star.js +80 -0
- package/dist/star.js.map +1 -0
- package/dist/templates/audio.d.ts +14 -0
- package/dist/templates/audio.js +15 -0
- package/dist/templates/audio.js.map +1 -0
- package/dist/templates/color-image.d.ts +22 -0
- package/dist/templates/color-image.js +23 -0
- package/dist/templates/color-image.js.map +1 -0
- package/dist/templates/donut.d.ts +22 -0
- package/dist/templates/donut.js +23 -0
- package/dist/templates/donut.js.map +1 -0
- package/dist/templates/ellipse.d.ts +21 -0
- package/dist/templates/ellipse.js +22 -0
- package/dist/templates/ellipse.js.map +1 -0
- package/dist/templates/gif-image.d.ts +14 -0
- package/dist/templates/gif-image.js +15 -0
- package/dist/templates/gif-image.js.map +1 -0
- package/dist/templates/gray-image.d.ts +22 -0
- package/dist/templates/gray-image.js +23 -0
- package/dist/templates/gray-image.js.map +1 -0
- package/dist/templates/index.d.ts +74 -0
- package/dist/templates/index.js +15 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/polygon.d.ts +22 -0
- package/dist/templates/polygon.js +25 -0
- package/dist/templates/polygon.js.map +1 -0
- package/dist/templates/polyline.d.ts +22 -0
- package/dist/templates/polyline.js +25 -0
- package/dist/templates/polyline.js.map +1 -0
- package/dist/templates/rect.d.ts +21 -0
- package/dist/templates/rect.js +22 -0
- package/dist/templates/rect.js.map +1 -0
- package/dist/templates/star.d.ts +23 -0
- package/dist/templates/star.js +24 -0
- package/dist/templates/star.js.map +1 -0
- package/dist/templates/text.d.ts +27 -0
- package/dist/templates/text.js +28 -0
- package/dist/templates/text.js.map +1 -0
- package/dist/templates/triangle.d.ts +23 -0
- package/dist/templates/triangle.js +24 -0
- package/dist/templates/triangle.js.map +1 -0
- package/dist/text.d.ts +6 -0
- package/dist/text.js +11 -0
- package/dist/text.js.map +1 -0
- package/dist/triangle.d.ts +14 -0
- package/dist/triangle.js +75 -0
- package/dist/triangle.js.map +1 -0
- package/icons/audio.png +0 -0
- package/icons/both-arrow.png +0 -0
- package/icons/color-image.png +0 -0
- package/icons/container.png +0 -0
- package/icons/dash.png +0 -0
- package/icons/donut.png +0 -0
- package/icons/ellipse.png +0 -0
- package/icons/gif-image.png +0 -0
- package/icons/global-reference.png +0 -0
- package/icons/gray-image.png +0 -0
- package/icons/humidity-sensor.png +0 -0
- package/icons/info-window.png +0 -0
- package/icons/line.png +0 -0
- package/icons/local-reference.png +0 -0
- package/icons/no-image.png +0 -0
- package/icons/ortholine.png +0 -0
- package/icons/person.png +0 -0
- package/icons/polygon.png +0 -0
- package/icons/polyline.png +0 -0
- package/icons/popup.png +0 -0
- package/icons/rect.png +0 -0
- package/icons/single-arrow.png +0 -0
- package/icons/star.png +0 -0
- package/icons/text.png +0 -0
- package/icons/triangle.png +0 -0
- package/package.json +61 -0
- package/src/anchors/ellipse-anchors.ts +46 -0
- package/src/audio.ts +173 -0
- package/src/cloud.ts +40 -0
- package/src/donut.ts +92 -0
- package/src/ellipse.ts +90 -0
- package/src/gif-view.ts +146 -0
- package/src/image-view.ts +215 -0
- package/src/index.ts +16 -0
- package/src/outline/ellipse-outline.ts +15 -0
- package/src/polygon.ts +103 -0
- package/src/polyline.ts +122 -0
- package/src/rect.ts +71 -0
- package/src/star.ts +104 -0
- package/src/templates/audio.ts +15 -0
- package/src/templates/color-image.ts +23 -0
- package/src/templates/donut.ts +23 -0
- package/src/templates/ellipse.ts +22 -0
- package/src/templates/gif-image.ts +15 -0
- package/src/templates/gray-image.ts +23 -0
- package/src/templates/index.ts +16 -0
- package/src/templates/polygon.ts +25 -0
- package/src/templates/polyline.ts +25 -0
- package/src/templates/rect.ts +22 -0
- package/src/templates/star.ts +24 -0
- package/src/templates/text.ts +28 -0
- package/src/templates/triangle.ts +24 -0
- package/src/text.ts +12 -0
- package/src/triangle.ts +87 -0
- package/test/basic-test.html +63 -0
- package/test/index.html +22 -0
- package/things-scene.config.js +5 -0
- package/tsconfig.json +23 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { error, Component, ComponentNature, Properties, RectPath, Shape } from '@hatiolab/things-scene'
|
|
6
|
+
|
|
7
|
+
const NATURE: ComponentNature = {
|
|
8
|
+
mutable: false,
|
|
9
|
+
resizable: true,
|
|
10
|
+
rotatable: true,
|
|
11
|
+
properties: [
|
|
12
|
+
{
|
|
13
|
+
type: 'image-selector',
|
|
14
|
+
label: 'image-src',
|
|
15
|
+
name: 'src',
|
|
16
|
+
property: {
|
|
17
|
+
displayField: 'id',
|
|
18
|
+
displayFullUrl: true,
|
|
19
|
+
baseUrlAlias: '$base_url',
|
|
20
|
+
defaultStorage: 'scene-image',
|
|
21
|
+
storageFilters: {
|
|
22
|
+
type: Array,
|
|
23
|
+
value: [
|
|
24
|
+
{
|
|
25
|
+
name: 'category',
|
|
26
|
+
value: 'image'
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
useUpload: true
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
type: 'select',
|
|
35
|
+
label: 'cross-origin',
|
|
36
|
+
name: 'crossOrigin',
|
|
37
|
+
property: {
|
|
38
|
+
options: ['', 'anonymous', 'use-credentials']
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
'value-property': 'src',
|
|
43
|
+
help: 'scene/component/image-view'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const NOIMAGE_DATA_URI =
|
|
47
|
+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABIBAMAAAD7Se1QAAAAIVBMVEUAAABHcEwBAQEREREBAQEEBAQGBgYLCwsDAwMDAwMICAi6HF9tAAAAC3RSTlNNAEAERiMYCS41Eac10lYAAAEgSURBVHhe7dY9asQwEAXgh7DNertNiJy48pIitY3SB7bYdk0ukL1BDDmA9gZecoH4pmFQ3MQayUMguPBrNPD4wD9TCMvJmt3M/AtYwXOlXiWgqADVCUBD46MAnGhMBaCiUQmAm8VA/Eh/eWl9Fn5WcxD+OLuRrUYJDKLluwH2InACUgkoACSdADxQc50Bytadb9RkM0CT13TcvlCT1HFg8UTHvasuUVACCa3El6u2UdD8LFTlKhUFFgA+d3dj10aABkUN72N3jAADCrJq7PIIsPidcxBoTHIIAjMFmyCwmGYIAA1P9gFgfCANAOsDSccCDW+uLDB+kLGg94OkZoAGkwsDDAe2DOg5oPxAg03rBR88OHpBz4N8UVeHFSwma74BTW6Ge4rIRa4AAAAASUVORK5CYII='
|
|
48
|
+
|
|
49
|
+
export default class ImageView extends RectPath(Shape) {
|
|
50
|
+
static NOIMAGE?: any
|
|
51
|
+
|
|
52
|
+
static get noimage() {
|
|
53
|
+
if (!ImageView.NOIMAGE) {
|
|
54
|
+
ImageView.NOIMAGE = new Image()
|
|
55
|
+
ImageView.NOIMAGE.src = NOIMAGE_DATA_URI
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return ImageView.NOIMAGE
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_offcanvas?: HTMLCanvasElement
|
|
62
|
+
_image?: any
|
|
63
|
+
|
|
64
|
+
dispose() {
|
|
65
|
+
super.dispose()
|
|
66
|
+
delete this._offcanvas
|
|
67
|
+
delete this._image
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
render(ctx: CanvasRenderingContext2D) {
|
|
71
|
+
var { left, top, width, height, isGray = false, alpha = 1, src } = this.state
|
|
72
|
+
|
|
73
|
+
this.prepareIf(!this._image && src)
|
|
74
|
+
|
|
75
|
+
// 박스 그리기
|
|
76
|
+
ctx.beginPath()
|
|
77
|
+
ctx.globalAlpha *= alpha
|
|
78
|
+
|
|
79
|
+
if (this._image && this._image.complete) {
|
|
80
|
+
if (isGray && this._offcanvas) {
|
|
81
|
+
ctx.drawImage(this._offcanvas, left, top, width, height)
|
|
82
|
+
} else {
|
|
83
|
+
try {
|
|
84
|
+
ctx.drawImage(this._image, left, top, width, height)
|
|
85
|
+
} catch (e) {
|
|
86
|
+
ctx.drawImage(ImageView.noimage, left, top, width, height)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
!this.app.isViewMode && ctx.drawImage(ImageView.noimage, left, top, width, height)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get nature() {
|
|
95
|
+
return NATURE
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
get hasTextProperty() {
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
ready() {
|
|
103
|
+
super.ready()
|
|
104
|
+
this.prepareIf(!this._image && this.state.src)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
prepare(resolve: (ret?: any) => void, reject: (e?: any) => void) {
|
|
108
|
+
var { src, crossOrigin } = this.state
|
|
109
|
+
|
|
110
|
+
if (!src) {
|
|
111
|
+
resolve(this)
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this._image = new Image()
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
if (crossOrigin) {
|
|
119
|
+
this._image.crossOrigin = crossOrigin
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this._image.src = this.app.url(src) || ''
|
|
123
|
+
} catch (e) {
|
|
124
|
+
reject(e)
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this._image.onload = () => {
|
|
129
|
+
if (this.get('isGray')) {
|
|
130
|
+
let width = this._image.width
|
|
131
|
+
let height = this._image.height
|
|
132
|
+
|
|
133
|
+
this._offcanvas = Component.createCanvas(width, height)
|
|
134
|
+
|
|
135
|
+
let offcontext = this._offcanvas!.getContext('2d') as CanvasRenderingContext2D
|
|
136
|
+
offcontext!.drawImage(this._image, 0, 0)
|
|
137
|
+
|
|
138
|
+
let imageData = makeGrayImage(offcontext, width, height)
|
|
139
|
+
offcontext!.putImageData(imageData!, 0, 0)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
resolve(this)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
this._image.onerror = (e: any) => {
|
|
146
|
+
if (this._image && !this._image.currentSrc) this._image = null
|
|
147
|
+
reject(e)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
get src() {
|
|
152
|
+
return this.get('src')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
set src(src) {
|
|
156
|
+
this.set('src', src)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
onchange(after: Properties, before: Properties) {
|
|
160
|
+
if (after.hasOwnProperty('src') || after.hasOwnProperty('isGray')) {
|
|
161
|
+
delete this._offcanvas
|
|
162
|
+
delete this._image
|
|
163
|
+
this.prepareIf(after.src)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
ondropfile(transfered: DataTransferItemList, files: FileList) {
|
|
168
|
+
for (let i = 0; i < transfered.length; i++) {
|
|
169
|
+
if (transfered[i].type.startsWith('image/')) {
|
|
170
|
+
this.src = files[i]
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function makeGrayImage(ctx: CanvasRenderingContext2D, width: number, height: number) {
|
|
178
|
+
try {
|
|
179
|
+
var img = ctx.getImageData(0, 0, width, height)
|
|
180
|
+
} catch (e: any) {
|
|
181
|
+
error('Get Image Data Error: ' + e.message)
|
|
182
|
+
return null
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
var data = img.data
|
|
186
|
+
// Loop through data.
|
|
187
|
+
for (let i = 0; i < width * height * 4; i += 4) {
|
|
188
|
+
// First bytes are red bytes.
|
|
189
|
+
// Get red value.
|
|
190
|
+
let red = data[i]
|
|
191
|
+
|
|
192
|
+
// Second bytes are green bytes.
|
|
193
|
+
// Get green value.
|
|
194
|
+
let green = data[i + 1]
|
|
195
|
+
|
|
196
|
+
// Third bytes are blue bytes.
|
|
197
|
+
// Get blue value.
|
|
198
|
+
let blue = data[i + 2]
|
|
199
|
+
|
|
200
|
+
// Fourth bytes are alpha bytes
|
|
201
|
+
// We don't care about alpha here.
|
|
202
|
+
// Add the three values and divide by three.
|
|
203
|
+
// Make it an integer.
|
|
204
|
+
let gray = parseInt(String((red + green + blue) / 3))
|
|
205
|
+
|
|
206
|
+
// Assign average to red, green, and blue.
|
|
207
|
+
img.data[i] = gray
|
|
208
|
+
img.data[i + 1] = gray
|
|
209
|
+
img.data[i + 2] = gray
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return img
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
Component.register('image-view', ImageView)
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { default as Ellipse } from './ellipse'
|
|
6
|
+
export { default as Rect } from './rect'
|
|
7
|
+
export { default as Polygon } from './polygon'
|
|
8
|
+
export { default as Polyline } from './polyline'
|
|
9
|
+
export { default as ImageView } from './image-view'
|
|
10
|
+
export { default as GifView } from './gif-view'
|
|
11
|
+
export { default as AudioPlayer } from './audio'
|
|
12
|
+
export { default as Text } from './text'
|
|
13
|
+
|
|
14
|
+
export { default as Triangle } from './triangle'
|
|
15
|
+
export { default as Donut } from './donut'
|
|
16
|
+
export { default as Star } from './star'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Component } from '@hatiolab/things-scene'
|
|
6
|
+
|
|
7
|
+
export default function ellipseOutline(component: Component, progress: number) {
|
|
8
|
+
var { cx, cy, rx, ry } = component.model
|
|
9
|
+
var theta = Math.PI * 2 * progress
|
|
10
|
+
|
|
11
|
+
var x = cx + rx * Math.cos(theta)
|
|
12
|
+
var y = cy + ry * Math.sin(theta)
|
|
13
|
+
|
|
14
|
+
return component.transcoordS2T(x, y)
|
|
15
|
+
}
|
package/src/polygon.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Component, ComponentNature, DIMENSION, POSITION, Properties, RectPath, Shape } from '@hatiolab/things-scene'
|
|
6
|
+
|
|
7
|
+
var controlHandler = {
|
|
8
|
+
ondragstart: function (point: POSITION, index: number, component: Component) {
|
|
9
|
+
component.mutatePath(null, function (path: Array<DIMENSION>) {
|
|
10
|
+
path.splice(index + 1, 0, point)
|
|
11
|
+
})
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
ondragmove: function (point: POSITION, index: number, component: Component) {
|
|
15
|
+
component.mutatePath(null, function (path: Array<DIMENSION>) {
|
|
16
|
+
path[index + 1] = point
|
|
17
|
+
})
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
ondragend: function (point: POSITION, index: number, component: Component) {}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const NATURE: ComponentNature = {
|
|
24
|
+
mutable: true,
|
|
25
|
+
resizable: false,
|
|
26
|
+
rotatable: true,
|
|
27
|
+
properties: [
|
|
28
|
+
{
|
|
29
|
+
type: 'number',
|
|
30
|
+
label: 'round',
|
|
31
|
+
name: 'round',
|
|
32
|
+
property: {
|
|
33
|
+
min: 0,
|
|
34
|
+
max: 100,
|
|
35
|
+
step: 1
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
help: 'scene/component/polygon'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default class Polygon extends Shape {
|
|
43
|
+
is3dish() {
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get mutable() {
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get pathExtendable() {
|
|
52
|
+
return true
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get path() {
|
|
56
|
+
return this.state.path
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
set path(path) {
|
|
60
|
+
this.set('path', path)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
contains(x: number, y: number) {
|
|
64
|
+
var path = this.state.path as Array<DIMENSION>
|
|
65
|
+
var result = false
|
|
66
|
+
|
|
67
|
+
path.forEach((p, idx) => {
|
|
68
|
+
let j = (idx + path.length + 1) % path.length
|
|
69
|
+
|
|
70
|
+
let x1 = p.x
|
|
71
|
+
let y1 = p.y
|
|
72
|
+
let x2 = path[j].x
|
|
73
|
+
let y2 = path[j].y
|
|
74
|
+
|
|
75
|
+
if (y1 > y != y2 > y && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1) result = !result
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
return result
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get controls() {
|
|
82
|
+
// 폴리곤에서의 control은 새로운 path를 추가하는 포인트이다.
|
|
83
|
+
var path = this.path as Array<DIMENSION>
|
|
84
|
+
|
|
85
|
+
return path.map((p1, i) => {
|
|
86
|
+
let p2 = path[i + 1 >= path.length ? 0 : i + 1]
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
x: (p1.x + p2.x) / 2,
|
|
90
|
+
y: (p1.y + p2.y) / 2,
|
|
91
|
+
handler: controlHandler
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get nature() {
|
|
97
|
+
return NATURE
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
Component.memoize(Polygon.prototype, 'controls', false)
|
|
102
|
+
|
|
103
|
+
Component.register('polygon', Polygon)
|
package/src/polyline.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import { Component, ComponentNature, Properties, Line, POSITION } from '@hatiolab/things-scene'
|
|
5
|
+
|
|
6
|
+
var controlHandler = {
|
|
7
|
+
ondragstart: function (point: POSITION, index: number, component: Component) {
|
|
8
|
+
component.mutatePath(null, function (path) {
|
|
9
|
+
path.splice(index, 0, point) // array.insert(index, point) 의 의미임.
|
|
10
|
+
})
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
ondragmove: function (point: POSITION, index: number, component: Component) {
|
|
14
|
+
component.mutatePath(null, function (path) {
|
|
15
|
+
path[index] = point
|
|
16
|
+
})
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
ondragend: function (point: POSITION, index: number, component: Component) {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const NATURE: ComponentNature = {
|
|
23
|
+
mutable: false,
|
|
24
|
+
resizable: false,
|
|
25
|
+
rotatable: false,
|
|
26
|
+
properties: [
|
|
27
|
+
{
|
|
28
|
+
type: 'number',
|
|
29
|
+
label: 'round',
|
|
30
|
+
name: 'round',
|
|
31
|
+
property: {
|
|
32
|
+
min: 0,
|
|
33
|
+
max: 100,
|
|
34
|
+
step: 1
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
help: 'scene/component/polyline'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default class Polyline extends Line {
|
|
42
|
+
_fromEnd: any
|
|
43
|
+
_toEnd: any
|
|
44
|
+
|
|
45
|
+
get pathExtendable() {
|
|
46
|
+
return true
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get path() {
|
|
50
|
+
const { from, to } = this.state
|
|
51
|
+
const { path } = this.state
|
|
52
|
+
|
|
53
|
+
return [
|
|
54
|
+
this.fromEnd?.position || from?.position || path[0],
|
|
55
|
+
...path.slice(1, -1),
|
|
56
|
+
this.toEnd?.position || to?.position || path[path.length - 1]
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
set path(path) {
|
|
61
|
+
const { from, to } = this.state
|
|
62
|
+
|
|
63
|
+
delete this._fromEnd
|
|
64
|
+
delete this._toEnd
|
|
65
|
+
|
|
66
|
+
this.set({
|
|
67
|
+
from: {
|
|
68
|
+
...from,
|
|
69
|
+
position: path[0]
|
|
70
|
+
},
|
|
71
|
+
to: {
|
|
72
|
+
...to,
|
|
73
|
+
position: path[path.length - 1]
|
|
74
|
+
},
|
|
75
|
+
path
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get controls() {
|
|
80
|
+
// 폴리라인에서의 control은 새로운 path를 추가하는 포인트이다.
|
|
81
|
+
var path = this.path
|
|
82
|
+
var controls = []
|
|
83
|
+
|
|
84
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
85
|
+
let p1 = path[i]
|
|
86
|
+
let p2 = path[i + 1]
|
|
87
|
+
|
|
88
|
+
if (i == 0) {
|
|
89
|
+
controls.push({
|
|
90
|
+
x: p1.x,
|
|
91
|
+
y: p1.y,
|
|
92
|
+
handler: controlHandler
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
controls.push({
|
|
97
|
+
x: (p1.x + p2.x) / 2,
|
|
98
|
+
y: (p1.y + p2.y) / 2,
|
|
99
|
+
handler: controlHandler
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
if (i == path.length - 2) {
|
|
103
|
+
controls.push({
|
|
104
|
+
x: p2.x,
|
|
105
|
+
y: p2.y,
|
|
106
|
+
handler: controlHandler
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return controls
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get nature() {
|
|
115
|
+
return NATURE
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* target anchor의 움직임이 반영되지 못하므로, 일단 controls memoize를 제거함. */
|
|
120
|
+
// Component.memoize(Polyline.prototype, 'controls', false)
|
|
121
|
+
|
|
122
|
+
Component.register('polyline', Polyline)
|
package/src/rect.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Component, ComponentNature, Connectable, POSITION, Properties, RectPath, Shape } from '@hatiolab/things-scene'
|
|
6
|
+
|
|
7
|
+
const NATURE: ComponentNature = {
|
|
8
|
+
mutable: false,
|
|
9
|
+
resizable: true,
|
|
10
|
+
rotatable: true,
|
|
11
|
+
properties: [
|
|
12
|
+
{
|
|
13
|
+
type: 'number',
|
|
14
|
+
label: 'round',
|
|
15
|
+
name: 'round',
|
|
16
|
+
property: {
|
|
17
|
+
min: 0
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
help: 'scene/component/rect'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var controlHandler = {
|
|
25
|
+
ondragmove: function (point: POSITION, index: number, component: Component) {
|
|
26
|
+
var { left, top, width, height } = component.model
|
|
27
|
+
|
|
28
|
+
var transcoorded = component.transcoordP2S(point.x, point.y)
|
|
29
|
+
var round = ((transcoorded.x - left) / (width / 2)) * 100
|
|
30
|
+
|
|
31
|
+
round = safeRound(round, width, height)
|
|
32
|
+
|
|
33
|
+
component.set({
|
|
34
|
+
round
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function safeRound(round: number, width: number, height: number) {
|
|
40
|
+
var max = width > height ? (height / width) * 100 : 100
|
|
41
|
+
|
|
42
|
+
if (round >= max) round = max
|
|
43
|
+
else if (round <= 0) round = 0
|
|
44
|
+
|
|
45
|
+
return round
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default class Rect extends Connectable(RectPath(Shape)) {
|
|
49
|
+
is3dish() {
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get controls() {
|
|
54
|
+
var { left, top, width, round, height } = this.state
|
|
55
|
+
round = round == undefined ? 0 : safeRound(round, width, height)
|
|
56
|
+
|
|
57
|
+
return [
|
|
58
|
+
{
|
|
59
|
+
x: left + (width / 2) * (round / 100),
|
|
60
|
+
y: top,
|
|
61
|
+
handler: controlHandler
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get nature() {
|
|
67
|
+
return NATURE
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
Component.register('rect', Rect)
|
package/src/star.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Component, ComponentNature, Ellipse, POSITION } from '@hatiolab/things-scene'
|
|
6
|
+
|
|
7
|
+
const NATURE: ComponentNature = {
|
|
8
|
+
mutable: false,
|
|
9
|
+
resizable: true,
|
|
10
|
+
rotatable: true,
|
|
11
|
+
properties: [
|
|
12
|
+
{
|
|
13
|
+
type: 'number',
|
|
14
|
+
label: 'ratio',
|
|
15
|
+
name: 'ratio',
|
|
16
|
+
property: 'ratio'
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
type: 'number',
|
|
20
|
+
label: 'wing',
|
|
21
|
+
name: 'wing',
|
|
22
|
+
property: 'wing'
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
help: 'scene/component/star'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var controlHandler = {
|
|
29
|
+
ondragmove: function (point: POSITION, index: number, component: Component) {
|
|
30
|
+
var controls = component.controls
|
|
31
|
+
var { cy, ry } = component.model
|
|
32
|
+
|
|
33
|
+
var transcoorded = component.transcoordP2S(point.x, point.y)
|
|
34
|
+
|
|
35
|
+
var ratio = ((transcoorded.y - cy) / ry) * 100 + 100
|
|
36
|
+
|
|
37
|
+
if (ratio >= 100) ratio = 100
|
|
38
|
+
else if (ratio <= 0) ratio = 0
|
|
39
|
+
|
|
40
|
+
component.set({ ratio }) // ratio: ratio => ratio
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default class Star extends Ellipse {
|
|
45
|
+
is3dish() {
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
render(ctx: CanvasRenderingContext2D) {
|
|
50
|
+
var { ratio = 30, wing = 5, cx, cy, rx, ry, startAngle, endAngle, anticlockwise } = this.state
|
|
51
|
+
|
|
52
|
+
// 박스 그리기
|
|
53
|
+
|
|
54
|
+
if (wing < 3) return
|
|
55
|
+
|
|
56
|
+
const RADIAN = 1.5707963267948966 // 90도 뒤틀기
|
|
57
|
+
var a = (Math.PI * 2) / wing
|
|
58
|
+
var xRatio = rx - (ratio / 100) * rx
|
|
59
|
+
var yRatio = ry - (ratio / 100) * ry
|
|
60
|
+
|
|
61
|
+
ctx.save()
|
|
62
|
+
ctx.beginPath()
|
|
63
|
+
|
|
64
|
+
ctx.translate(cx, cy)
|
|
65
|
+
|
|
66
|
+
ctx.moveTo(rx * Math.cos(-RADIAN), ry * Math.sin(-RADIAN))
|
|
67
|
+
ctx.lineTo(
|
|
68
|
+
((rx - xRatio) * (Math.cos(a - RADIAN) + Math.cos(0 - RADIAN))) / 2,
|
|
69
|
+
((ry - yRatio) * (Math.sin(a - RADIAN) + Math.sin(0 - RADIAN))) / 2
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
for (var i = 1; i < wing; i++) {
|
|
73
|
+
ctx.lineTo(rx * Math.cos(a * i - RADIAN), ry * Math.sin(a * i - RADIAN))
|
|
74
|
+
|
|
75
|
+
ctx.lineTo(
|
|
76
|
+
((rx - xRatio) * (Math.cos(a * (i + 1) - RADIAN) + Math.cos(a * i - RADIAN))) / 2,
|
|
77
|
+
((ry - yRatio) * (Math.sin(a * (i + 1) - RADIAN) + Math.sin(a * i - RADIAN))) / 2
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
// ratio /= 1.5;
|
|
81
|
+
ctx.closePath()
|
|
82
|
+
ctx.restore()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get controls() {
|
|
86
|
+
var { cx, cy, ry, ratio } = this.state
|
|
87
|
+
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
x: cx,
|
|
91
|
+
y: cy - ry + ry * (ratio / 100),
|
|
92
|
+
handler: controlHandler
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get nature() {
|
|
98
|
+
return NATURE
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
Component.memoize(Star.prototype, 'controls', false)
|
|
103
|
+
|
|
104
|
+
Component.register('star', Star)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const audio = new URL('../../icons/audio.png', import.meta.url).href
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
type: 'audio',
|
|
5
|
+
description: 'audio',
|
|
6
|
+
icon: audio,
|
|
7
|
+
group: 'textAndMedia',
|
|
8
|
+
model: {
|
|
9
|
+
type: 'audio',
|
|
10
|
+
left: 100,
|
|
11
|
+
top: 100,
|
|
12
|
+
width: 100,
|
|
13
|
+
height: 100
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const colorImage = new URL('../../icons/color-image.png', import.meta.url).href
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
type: 'color image',
|
|
5
|
+
description: 'color image',
|
|
6
|
+
icon: colorImage,
|
|
7
|
+
group: 'textAndMedia',
|
|
8
|
+
model: {
|
|
9
|
+
type: 'image-view',
|
|
10
|
+
left: 100,
|
|
11
|
+
top: 100,
|
|
12
|
+
width: 100,
|
|
13
|
+
height: 100,
|
|
14
|
+
isGray: false,
|
|
15
|
+
fillStyle: '#fff',
|
|
16
|
+
strokeStyle: '#000',
|
|
17
|
+
alpha: 1,
|
|
18
|
+
hidden: false,
|
|
19
|
+
lineWidth: 1,
|
|
20
|
+
lineDash: 'solid',
|
|
21
|
+
lineCap: 'butt'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const donut = new URL('../../icons/donut.png', import.meta.url).href
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
type: 'donut',
|
|
5
|
+
description: 'donut shape',
|
|
6
|
+
icon: donut,
|
|
7
|
+
group: 'shape',
|
|
8
|
+
model: {
|
|
9
|
+
type: 'donut',
|
|
10
|
+
rx: 50,
|
|
11
|
+
ry: 50,
|
|
12
|
+
cx: 150,
|
|
13
|
+
cy: 150,
|
|
14
|
+
ratio: 30,
|
|
15
|
+
fillStyle: '#fff',
|
|
16
|
+
strokeStyle: '#000',
|
|
17
|
+
alpha: 1,
|
|
18
|
+
hidden: false,
|
|
19
|
+
lineWidth: 1,
|
|
20
|
+
lineDash: 'solid',
|
|
21
|
+
lineCap: 'butt'
|
|
22
|
+
}
|
|
23
|
+
}
|