cbvirtua 1.0.42 → 1.0.44

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 (23) hide show
  1. package/Signature.vue +366 -0
  2. package/canvas-event-system/build/canvas-event-system/EventSimulator.d.ts +20 -0
  3. package/canvas-event-system/build/canvas-event-system/EventSimulator.js +51 -0
  4. package/canvas-event-system/build/canvas-event-system/helpers.d.ts +3 -0
  5. package/canvas-event-system/build/canvas-event-system/helpers.js +21 -0
  6. package/canvas-event-system/build/canvas-event-system/index.d.ts +20 -0
  7. package/canvas-event-system/build/canvas-event-system/index.js +51 -0
  8. package/canvas-event-system/build/canvas-event-system/shapes/Base.d.ts +12 -0
  9. package/canvas-event-system/build/canvas-event-system/shapes/Base.js +26 -0
  10. package/canvas-event-system/build/canvas-event-system/shapes/Circle.d.ts +15 -0
  11. package/canvas-event-system/build/canvas-event-system/shapes/Circle.js +34 -0
  12. package/canvas-event-system/build/canvas-event-system/shapes/Path.d.ts +0 -0
  13. package/canvas-event-system/build/canvas-event-system/shapes/Path.js +0 -0
  14. package/canvas-event-system/build/canvas-event-system/shapes/Rect.d.ts +16 -0
  15. package/canvas-event-system/build/canvas-event-system/shapes/Rect.js +33 -0
  16. package/canvas-event-system/build/canvas-event-system/shapes/index.d.ts +4 -0
  17. package/canvas-event-system/build/canvas-event-system/shapes/index.js +4 -0
  18. package/canvas-event-system/build/canvas-event-system/shapes/types.d.ts +19 -0
  19. package/canvas-event-system/build/canvas-event-system/shapes/types.js +9 -0
  20. package/canvas-event-system/build/index.d.ts +1 -0
  21. package/canvas-event-system/build/index.js +24 -0
  22. package/canvas-event-system/tsconfig.json +1 -1
  23. package/package.json +1 -1
package/Signature.vue ADDED
@@ -0,0 +1,366 @@
1
+ <template>
2
+ <div class="canvasBox">
3
+ <div class="canvasWrap">
4
+ <canvas id="canvas2"></canvas>
5
+ <canvas id="canvas"></canvas>
6
+ </div>
7
+ </div>
8
+ </template>
9
+
10
+ <script setup>
11
+ import { onMounted } from 'vue'
12
+ import { getStroke } from 'perfect-freehand'
13
+
14
+ onMounted(() => {
15
+ const canvas = document.getElementById('canvas')
16
+ const canvas2 = document.getElementById('canvas2')
17
+ const canvasWidth = 500
18
+ const canvasHeight = 500
19
+ const ratio = Math.max(window.devicePixelRatio, 2)
20
+
21
+ const initCanvas = canvas => {
22
+ canvas.width = canvasWidth * ratio
23
+ canvas.height = canvasHeight * ratio
24
+ canvas.style.width = canvasWidth + 'px'
25
+ canvas.style.height = canvasHeight + 'px'
26
+ const ctx = canvas.getContext('2d')
27
+ ctx.scale(ratio, ratio)
28
+ return ctx
29
+ }
30
+ const ctx = initCanvas(canvas)
31
+ const ctx2 = initCanvas(canvas2)
32
+
33
+ const rect = canvas.getBoundingClientRect()
34
+ const windowToCanvas = e => {
35
+ const x = e.clientX - rect.left
36
+ const y = e.clientY - rect.top
37
+ return {
38
+ x,
39
+ y
40
+ }
41
+ }
42
+
43
+ const average = (a, b) => (a + b) / 2
44
+
45
+ const getTwoPointDistance = (x1, y1, x2, y2) => {
46
+ return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2))
47
+ }
48
+
49
+ // 增量绘制
50
+ const demo = () => {
51
+ let isMousedown = false
52
+ let lastPos = {
53
+ x: 0,
54
+ y: 0
55
+ }
56
+ canvas.addEventListener('mousedown', e => {
57
+ isMousedown = true
58
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight)
59
+ lastPos = windowToCanvas(e)
60
+ })
61
+ window.addEventListener('mousemove', e => {
62
+ if (!isMousedown) return
63
+ ctx.beginPath()
64
+ ctx.moveTo(lastPos.x, lastPos.y)
65
+ lastPos = windowToCanvas(e)
66
+ ctx.lineTo(lastPos.x, lastPos.y)
67
+ ctx.lineWidth = 5
68
+ ctx.stroke()
69
+ })
70
+ window.addEventListener('mouseup', () => {
71
+ isMousedown = false
72
+ })
73
+ }
74
+ // demo()
75
+
76
+ // 重新绘制
77
+ const demo2 = () => {
78
+ let isMousedown = false
79
+ let pointList = []
80
+ let lastPos = null
81
+ canvas.addEventListener('mousedown', e => {
82
+ isMousedown = true
83
+ lastPos = windowToCanvas(e)
84
+ pointList.push(lastPos)
85
+ })
86
+ window.addEventListener('mousemove', e => {
87
+ if (!isMousedown) return
88
+ const curPos = windowToCanvas(e)
89
+ const distance = getTwoPointDistance(
90
+ curPos.x,
91
+ curPos.y,
92
+ lastPos.x,
93
+ lastPos.y
94
+ )
95
+ if (distance <= 4) {
96
+ return
97
+ }
98
+ lastPos = curPos
99
+ pointList.push(curPos)
100
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight)
101
+ ctx.beginPath()
102
+ pointList.forEach((point, index) => {
103
+ if (index === 0) {
104
+ ctx.moveTo(point.x, point.y)
105
+ } else {
106
+ ctx.lineTo(point.x, point.y)
107
+ }
108
+ })
109
+ ctx.lineWidth = 5
110
+ ctx.stroke()
111
+ })
112
+ window.addEventListener('mouseup', () => {
113
+ isMousedown = false
114
+ pointList = []
115
+ })
116
+ }
117
+ // demo2()
118
+
119
+ // 曲线连接
120
+ const demo3 = () => {
121
+ let isMousedown = false
122
+ let pointList = []
123
+ let lastPos = null
124
+ canvas.addEventListener('mousedown', e => {
125
+ isMousedown = true
126
+ lastPos = windowToCanvas(e)
127
+ pointList.push(lastPos)
128
+ })
129
+ window.addEventListener('mousemove', e => {
130
+ if (!isMousedown) return
131
+ const curPos = windowToCanvas(e)
132
+ const distance = getTwoPointDistance(
133
+ curPos.x,
134
+ curPos.y,
135
+ lastPos.x,
136
+ lastPos.y
137
+ )
138
+ if (distance <= 4) {
139
+ return
140
+ }
141
+ lastPos = curPos
142
+ pointList.push(windowToCanvas(e))
143
+ const len = pointList.length
144
+ if (len < 4) {
145
+ return
146
+ }
147
+ const lastControlPoint = {
148
+ x: 0,
149
+ y: 0
150
+ }
151
+ const lastEndPoint = {
152
+ x: 0,
153
+ y: 0
154
+ }
155
+ let a = pointList[0]
156
+ let b = pointList[1]
157
+ const c = pointList[2]
158
+
159
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight)
160
+ ctx.beginPath()
161
+ ctx.moveTo(a.x, a.y)
162
+
163
+ // 记录控制点和终点
164
+ lastControlPoint.x = b.x
165
+ lastControlPoint.y = b.y
166
+ lastEndPoint.x = average(b.x, c.x)
167
+ lastEndPoint.y = average(b.y, c.y)
168
+
169
+ ctx.quadraticCurveTo(
170
+ lastControlPoint.x,
171
+ lastControlPoint.y,
172
+ lastEndPoint.x,
173
+ lastEndPoint.y
174
+ )
175
+
176
+ for (let i = 2, max = len - 1; i < max; i++) {
177
+ a = pointList[i]
178
+ b = pointList[i + 1]
179
+ // 更新控制点和终点
180
+ lastControlPoint.x =
181
+ lastEndPoint.x + (lastEndPoint.x - lastControlPoint.x)
182
+ lastControlPoint.y =
183
+ lastEndPoint.y + (lastEndPoint.y - lastControlPoint.y)
184
+ lastEndPoint.x = average(a.x, b.x)
185
+ lastEndPoint.y = average(a.y, b.y)
186
+ ctx.quadraticCurveTo(
187
+ lastControlPoint.x,
188
+ lastControlPoint.y,
189
+ lastEndPoint.x,
190
+ lastEndPoint.y
191
+ )
192
+ }
193
+
194
+ ctx.lineWidth = 5
195
+ ctx.stroke()
196
+ })
197
+ window.addEventListener('mouseup', () => {
198
+ isMousedown = false
199
+ pointList = []
200
+ })
201
+ }
202
+ // demo3()
203
+
204
+ const perfect = () => {
205
+ let isMousedown = false
206
+ let pointList = []
207
+ let lineList = []
208
+ let line = null
209
+ canvas.addEventListener('mousedown', e => {
210
+ isMousedown = true
211
+ pointList = []
212
+ pointList.push(windowToCanvas(e))
213
+ })
214
+ window.addEventListener('mousemove', e => {
215
+ if (!isMousedown) return
216
+ pointList.push(windowToCanvas(e))
217
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight)
218
+ lineList.forEach(item => {
219
+ ctx.fill(item)
220
+ })
221
+ const points = getStroke(pointList, {
222
+ size: 16,
223
+ thinning: 0.5,
224
+ smoothing: 0.5,
225
+ streamline: 0.5,
226
+ start: {
227
+ cap: true,
228
+ taper: 0,
229
+ easing: t => t
230
+ },
231
+ end: {
232
+ cap: true,
233
+ taper: 0,
234
+ easing: t => t
235
+ }
236
+ })
237
+ const pathData = getSvgPathFromStroke(points)
238
+ const path = new Path2D(pathData)
239
+ line = path
240
+ ctx.fill(path)
241
+ })
242
+ window.addEventListener('mouseup', () => {
243
+ isMousedown = false
244
+ lineList.push(line)
245
+ })
246
+
247
+ const getSvgPathFromStroke = points => {
248
+ const len = points.length
249
+ if (len < 4) {
250
+ return ''
251
+ }
252
+ let a = points[0]
253
+ let b = points[1]
254
+ const c = points[2]
255
+ let result = `M${a[0]},${a[1]} Q${b[0]},${b[1]} ${average(
256
+ b[0],
257
+ c[0]
258
+ )},${average(b[1], c[1])} T`
259
+ for (let i = 2, max = len - 1; i < max; i++) {
260
+ a = points[i]
261
+ b = points[i + 1]
262
+ result += `${average(a[0], b[0])},${average(a[1], b[1])} `
263
+ }
264
+ result += 'Z'
265
+ return result
266
+ }
267
+ }
268
+ // perfect()
269
+
270
+ // 两个canvas
271
+ const perfect2 = () => {
272
+ let isMousedown = false
273
+ let pointList = []
274
+ let lineList = []
275
+ let line = null
276
+ const clearCanvas = _ctx => {
277
+ _ctx.clearRect(0, 0, canvasWidth, canvasHeight)
278
+ }
279
+ canvas.addEventListener('mousedown', e => {
280
+ isMousedown = true
281
+ pointList = []
282
+ pointList.push(windowToCanvas(e))
283
+ })
284
+ window.addEventListener('mousemove', e => {
285
+ if (!isMousedown) return
286
+ pointList.push(windowToCanvas(e))
287
+ clearCanvas(ctx)
288
+ const points = getStroke(pointList, {
289
+ size: 16,
290
+ thinning: 0.5,
291
+ smoothing: 0.5,
292
+ streamline: 0.5,
293
+ start: {
294
+ cap: true,
295
+ taper: 0,
296
+ easing: t => t
297
+ },
298
+ end: {
299
+ cap: true,
300
+ taper: 0,
301
+ easing: t => t
302
+ }
303
+ })
304
+ const pathData = getSvgPathFromStroke(points)
305
+ const path = new Path2D(pathData)
306
+ line = path
307
+ ctx.fill(path)
308
+ })
309
+ window.addEventListener('mouseup', () => {
310
+ isMousedown = false
311
+ lineList.push(line)
312
+ // 绘制完成后就将图形移到canvas2
313
+ clearCanvas(ctx)
314
+ clearCanvas(ctx2)
315
+ lineList.forEach(item => {
316
+ ctx2.fill(item)
317
+ })
318
+ })
319
+
320
+ const getSvgPathFromStroke = points => {
321
+ const len = points.length
322
+ if (len < 4) {
323
+ return ''
324
+ }
325
+ let a = points[0]
326
+ let b = points[1]
327
+ const c = points[2]
328
+ let result = `M${a[0]},${a[1]} Q${b[0]},${b[1]} ${average(
329
+ b[0],
330
+ c[0]
331
+ )},${average(b[1], c[1])} T`
332
+ for (let i = 2, max = len - 1; i < max; i++) {
333
+ a = points[i]
334
+ b = points[i + 1]
335
+ result += `${average(a[0], b[0])},${average(a[1], b[1])} `
336
+ }
337
+ result += 'Z'
338
+ return result
339
+ }
340
+ }
341
+ perfect2()
342
+ })
343
+ </script>
344
+
345
+ <style lang="less" scoped>
346
+ .canvasBox {
347
+ width: 100%;
348
+ height: 100%;
349
+ display: flex;
350
+ justify-content: center;
351
+ align-items: center;
352
+
353
+ .canvasWrap {
354
+ position: relative;
355
+ width: 500px;
356
+ height: 500px;
357
+ }
358
+
359
+ canvas {
360
+ position: absolute;
361
+ left: 0;
362
+ top: 0;
363
+ border: 1px solid;
364
+ }
365
+ }
366
+ </style>
@@ -0,0 +1,20 @@
1
+ import { Listener, EventNames } from './shapes';
2
+ export interface Action {
3
+ type: ActionType;
4
+ id: string;
5
+ }
6
+ export declare enum ActionType {
7
+ Down = "DOWN",
8
+ Up = "Up",
9
+ Move = "MOVE"
10
+ }
11
+ export default class EventSimulator {
12
+ private listenersMap;
13
+ private lastDownId;
14
+ private lastMoveId;
15
+ addAction(action: Action, evt: MouseEvent): void;
16
+ addListeners(id: string, listeners: {
17
+ [eventName: string]: Listener[];
18
+ }): void;
19
+ fire(id: string, eventName: EventNames, evt: MouseEvent): void;
20
+ }
@@ -0,0 +1,51 @@
1
+ import { EventNames } from './shapes';
2
+ export var ActionType;
3
+ (function (ActionType) {
4
+ ActionType["Down"] = "DOWN";
5
+ ActionType["Up"] = "Up";
6
+ ActionType["Move"] = "MOVE";
7
+ })(ActionType || (ActionType = {}));
8
+ export default class EventSimulator {
9
+ listenersMap = {};
10
+ lastDownId;
11
+ lastMoveId;
12
+ addAction(action, evt) {
13
+ const { type, id } = action;
14
+ // mousemove
15
+ if (type === ActionType.Move) {
16
+ this.fire(id, EventNames.mousemove, evt);
17
+ }
18
+ // mouseover
19
+ // mouseenter
20
+ if (type === ActionType.Move && (!this.lastMoveId || this.lastMoveId !== id)) {
21
+ this.fire(id, EventNames.mouseenter, evt);
22
+ this.fire(this.lastMoveId, EventNames.mouseleave, evt);
23
+ }
24
+ // mousedown
25
+ if (type === ActionType.Down) {
26
+ this.fire(id, EventNames.mousedown, evt);
27
+ }
28
+ // mouseup
29
+ if (type === ActionType.Up) {
30
+ this.fire(id, EventNames.mouseup, evt);
31
+ }
32
+ // click
33
+ if (type === ActionType.Up && this.lastDownId === id) {
34
+ this.fire(id, EventNames.click, evt);
35
+ }
36
+ if (type === ActionType.Move) {
37
+ this.lastMoveId = action.id;
38
+ }
39
+ else if (type === ActionType.Down) {
40
+ this.lastDownId = action.id;
41
+ }
42
+ }
43
+ addListeners(id, listeners) {
44
+ this.listenersMap[id] = listeners;
45
+ }
46
+ fire(id, eventName, evt) {
47
+ if (this.listenersMap[id] && this.listenersMap[id][eventName]) {
48
+ this.listenersMap[id][eventName].forEach((listener) => listener(evt));
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,3 @@
1
+ export declare function idToRgba(id: string): string[];
2
+ export declare function rgbaToId(rgba: [number, number, number, number]): string;
3
+ export declare function createId(): string;
@@ -0,0 +1,21 @@
1
+ export function idToRgba(id) {
2
+ return id.split("-");
3
+ }
4
+ export function rgbaToId(rgba) {
5
+ return rgba.join("-");
6
+ }
7
+ const idPool = {};
8
+ export function createId() {
9
+ let id = createOnceId();
10
+ while (idPool[id]) {
11
+ id = createOnceId();
12
+ }
13
+ return id;
14
+ }
15
+ function createOnceId() {
16
+ return Array(3)
17
+ .fill(0)
18
+ .map(() => Math.ceil(Math.random() * 255))
19
+ .concat(255)
20
+ .join("-");
21
+ }
@@ -0,0 +1,20 @@
1
+ import { Shape } from './shapes/types';
2
+ export * from './shapes';
3
+ export declare class Stage {
4
+ private canvas;
5
+ private osCanvas;
6
+ private ctx;
7
+ private osCtx;
8
+ private dpr;
9
+ private shapes;
10
+ private eventSimulator;
11
+ constructor(canvas: HTMLCanvasElement);
12
+ add(shape: Shape): void;
13
+ private handleCreator;
14
+ /**
15
+ * Determine whether the current position is inside a certain shape, if it is, then return its id
16
+ * @param x
17
+ * @param y
18
+ */
19
+ private hitJudge;
20
+ }
@@ -0,0 +1,51 @@
1
+ import { rgbaToId } from './helpers';
2
+ import EventSimulator, { ActionType } from './EventSimulator';
3
+ export * from './shapes';
4
+ export class Stage {
5
+ canvas;
6
+ osCanvas;
7
+ ctx;
8
+ osCtx;
9
+ dpr;
10
+ shapes;
11
+ eventSimulator;
12
+ constructor(canvas) {
13
+ const dpr = window.devicePixelRatio;
14
+ canvas.width = parseInt(canvas.style.width) * dpr;
15
+ canvas.height = parseInt(canvas.style.height) * dpr;
16
+ this.canvas = canvas;
17
+ this.osCanvas = new OffscreenCanvas(canvas.width, canvas.height);
18
+ this.ctx = this.canvas.getContext('2d');
19
+ this.osCtx = this.osCanvas.getContext('2d');
20
+ this.ctx.scale(dpr, dpr);
21
+ this.osCtx.scale(dpr, dpr);
22
+ this.dpr = dpr;
23
+ this.canvas.addEventListener('mousedown', this.handleCreator(ActionType.Down));
24
+ this.canvas.addEventListener('mouseup', this.handleCreator(ActionType.Up));
25
+ this.canvas.addEventListener('mousemove', this.handleCreator(ActionType.Move));
26
+ this.shapes = new Set();
27
+ this.eventSimulator = new EventSimulator();
28
+ }
29
+ add(shape) {
30
+ const id = shape.getId();
31
+ this.eventSimulator.addListeners(id, shape.getListeners());
32
+ this.shapes.add(id);
33
+ shape.draw(this.ctx, this.osCtx);
34
+ }
35
+ handleCreator = (type) => (evt) => {
36
+ const x = evt.offsetX;
37
+ const y = evt.offsetY;
38
+ const id = this.hitJudge(x, y);
39
+ this.eventSimulator.addAction({ type, id }, evt);
40
+ };
41
+ /**
42
+ * Determine whether the current position is inside a certain shape, if it is, then return its id
43
+ * @param x
44
+ * @param y
45
+ */
46
+ hitJudge(x, y) {
47
+ const rgba = Array.from(this.osCtx.getImageData(x * this.dpr, y * this.dpr, 1, 1).data);
48
+ const id = rgbaToId(rgba);
49
+ return this.shapes.has(id) ? id : undefined;
50
+ }
51
+ }
@@ -0,0 +1,12 @@
1
+ import { EventNames, Listener, Shape } from './types';
2
+ export default class Base implements Shape {
3
+ private listeners;
4
+ id: string;
5
+ constructor();
6
+ draw(ctx: CanvasRenderingContext2D, osCtx: OffscreenCanvasRenderingContext2D): void;
7
+ on(eventName: EventNames, listener: Listener): void;
8
+ getListeners(): {
9
+ [name: string]: Listener[];
10
+ };
11
+ getId(): string;
12
+ }
@@ -0,0 +1,26 @@
1
+ import { createId } from '../helpers';
2
+ export default class Base {
3
+ listeners;
4
+ id;
5
+ constructor() {
6
+ this.id = createId();
7
+ this.listeners = {};
8
+ }
9
+ draw(ctx, osCtx) {
10
+ throw new Error('Method not implemented.');
11
+ }
12
+ on(eventName, listener) {
13
+ if (this.listeners[eventName]) {
14
+ this.listeners[eventName].push(listener);
15
+ }
16
+ else {
17
+ this.listeners[eventName] = [listener];
18
+ }
19
+ }
20
+ getListeners() {
21
+ return this.listeners;
22
+ }
23
+ getId() {
24
+ return this.id;
25
+ }
26
+ }
@@ -0,0 +1,15 @@
1
+ import Base from './Base';
2
+ interface RectProps {
3
+ x: number;
4
+ y: number;
5
+ radius: number;
6
+ strokeWidth?: number;
7
+ strokeColor?: string;
8
+ fillColor?: string;
9
+ }
10
+ export default class Circle extends Base {
11
+ private props;
12
+ constructor(props: RectProps);
13
+ draw(ctx: CanvasRenderingContext2D, osCtx: OffscreenCanvasRenderingContext2D): void;
14
+ }
15
+ export {};
@@ -0,0 +1,34 @@
1
+ import { idToRgba } from '../helpers';
2
+ import Base from './Base';
3
+ export default class Circle extends Base {
4
+ props;
5
+ constructor(props) {
6
+ super();
7
+ this.props = props;
8
+ this.props.fillColor = this.props.fillColor || '#fff';
9
+ this.props.strokeColor = this.props.strokeColor || '#000';
10
+ this.props.strokeWidth = this.props.strokeWidth || 1;
11
+ }
12
+ draw(ctx, osCtx) {
13
+ const { x, y, radius, strokeColor, strokeWidth, fillColor } = this.props;
14
+ ctx.save();
15
+ ctx.beginPath();
16
+ ctx.fillStyle = fillColor;
17
+ ctx.strokeStyle = strokeColor;
18
+ ctx.lineWidth = strokeWidth;
19
+ ctx.arc(x, y, radius, 0, Math.PI * 2);
20
+ ctx.fill();
21
+ ctx.stroke();
22
+ ctx.restore();
23
+ const [r, g, b, a] = idToRgba(this.id);
24
+ osCtx.save();
25
+ osCtx.beginPath();
26
+ osCtx.fillStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
27
+ osCtx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
28
+ osCtx.lineWidth = strokeWidth;
29
+ osCtx.arc(x, y, radius, 0, Math.PI * 2);
30
+ osCtx.fill();
31
+ osCtx.stroke();
32
+ osCtx.restore();
33
+ }
34
+ }
@@ -0,0 +1,16 @@
1
+ import Base from './Base';
2
+ interface RectProps {
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ strokeWidth?: number;
8
+ strokeColor?: string;
9
+ fillColor?: string;
10
+ }
11
+ export default class Rect extends Base {
12
+ private props;
13
+ constructor(props: RectProps);
14
+ draw(ctx: CanvasRenderingContext2D, osCtx: OffscreenCanvasRenderingContext2D): void;
15
+ }
16
+ export {};
@@ -0,0 +1,33 @@
1
+ import { idToRgba } from '../helpers';
2
+ import Base from './Base';
3
+ export default class Rect extends Base {
4
+ props;
5
+ constructor(props) {
6
+ super();
7
+ this.props = props;
8
+ this.props.fillColor = this.props.fillColor || '#fff';
9
+ this.props.strokeColor = this.props.strokeColor || '#000';
10
+ this.props.strokeWidth = this.props.strokeWidth || 1;
11
+ }
12
+ draw(ctx, osCtx) {
13
+ const { x, y, width, height, strokeColor, strokeWidth, fillColor } = this.props;
14
+ ctx.save();
15
+ ctx.beginPath();
16
+ ctx.strokeStyle = strokeColor;
17
+ ctx.lineWidth = strokeWidth;
18
+ ctx.fillStyle = fillColor;
19
+ ctx.rect(x, y, width, height);
20
+ ctx.fill();
21
+ ctx.stroke();
22
+ ctx.restore();
23
+ const [r, g, b, a] = idToRgba(this.id);
24
+ osCtx.save();
25
+ osCtx.beginPath();
26
+ osCtx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
27
+ osCtx.fillStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
28
+ osCtx.rect(x, y, width, height);
29
+ osCtx.fill();
30
+ osCtx.stroke();
31
+ osCtx.restore();
32
+ }
33
+ }
@@ -0,0 +1,4 @@
1
+ import Rect from './Rect';
2
+ import Circle from './Circle';
3
+ export * from './types';
4
+ export { Rect, Circle };
@@ -0,0 +1,4 @@
1
+ import Rect from './Rect';
2
+ import Circle from './Circle';
3
+ export * from './types';
4
+ export { Rect, Circle };
@@ -0,0 +1,19 @@
1
+ export interface Shape {
2
+ draw(ctx: CanvasRenderingContext2D, osCtx: OffscreenCanvasRenderingContext2D): void;
3
+ on(name: string, listener: Listener): void;
4
+ getListeners(): {
5
+ [name: string]: Listener[];
6
+ };
7
+ getId(): string;
8
+ }
9
+ export interface Listener {
10
+ (evt: MouseEvent): void;
11
+ }
12
+ export declare enum EventNames {
13
+ click = "click",
14
+ mousedown = "mousedown",
15
+ mousemove = "mousemove",
16
+ mouseup = "mouseup",
17
+ mouseenter = "mouseenter",
18
+ mouseleave = "mouseleave"
19
+ }
@@ -0,0 +1,9 @@
1
+ export var EventNames;
2
+ (function (EventNames) {
3
+ EventNames["click"] = "click";
4
+ EventNames["mousedown"] = "mousedown";
5
+ EventNames["mousemove"] = "mousemove";
6
+ EventNames["mouseup"] = "mouseup";
7
+ EventNames["mouseenter"] = "mouseenter";
8
+ EventNames["mouseleave"] = "mouseleave";
9
+ })(EventNames || (EventNames = {}));
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import { Stage, Rect, Circle, EventNames } from './canvas-event-system';
2
+ const canvas = document.querySelector('#canvas');
3
+ const stage = new Stage(canvas);
4
+ const rect = new Rect({
5
+ x: 50,
6
+ y: 50,
7
+ width: 250,
8
+ height: 175,
9
+ fillColor: 'green',
10
+ });
11
+ const circle = new Circle({
12
+ x: 200,
13
+ y: 200,
14
+ radius: 100,
15
+ fillColor: 'red',
16
+ });
17
+ rect.on(EventNames.mousedown, () => console.log('rect mousedown'));
18
+ rect.on(EventNames.mouseup, () => console.log('rect mouseup'));
19
+ rect.on(EventNames.mouseenter, () => console.log('rect mouseenter'));
20
+ rect.on(EventNames.click, () => console.log('rect click'));
21
+ circle.on(EventNames.click, () => console.log('circle click!!'));
22
+ circle.on(EventNames.mouseleave, () => console.log('circle mouseleave!'));
23
+ stage.add(rect);
24
+ stage.add(circle);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "es5",
3
+ "target": "ESNext",
4
4
  "module": "ESNext",
5
5
  "jsx": "react",
6
6
  "jsxFactory": "h",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cbvirtua",
3
- "version": "1.0.42",
3
+ "version": "1.0.44",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {