canvas-editor-engine 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- package/Readme.md +118 -0
- package/dist/components/canvas.component.d.ts +21 -0
- package/dist/components/canvas.component.js +75 -0
- package/dist/components/excretions.component.d.ts +24 -0
- package/dist/components/excretions.component.js +192 -0
- package/dist/components/pipette.component.d.ts +23 -0
- package/dist/components/pipette.component.js +138 -0
- package/dist/components/slot.component.d.ts +10 -0
- package/dist/components/slot.component.js +20 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.js +29 -0
- package/dist/filters/collection/vague.d.ts +12 -0
- package/dist/filters/collection/vague.js +107 -0
- package/dist/filters/index.d.ts +2 -0
- package/dist/filters/index.js +5 -0
- package/dist/images/image.png +0 -0
- package/dist/images/sample.png +0 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +49 -0
- package/dist/services/component.service.d.ts +5 -0
- package/dist/services/component.service.js +37 -0
- package/dist/services/draw.service.d.ts +13 -0
- package/dist/services/draw.service.js +71 -0
- package/dist/services/tool.service.d.ts +10 -0
- package/dist/services/tool.service.js +58 -0
- package/dist/types/canvas.d.ts +10 -0
- package/dist/types/canvas.js +3 -0
- package/dist/types/cursor.d.ts +9 -0
- package/dist/types/cursor.js +3 -0
- package/dist/types/excreation.d.ts +24 -0
- package/dist/types/excreation.js +5 -0
- package/dist/types/excretion.d.ts +26 -0
- package/dist/types/excretion.js +5 -0
- package/dist/types/general.d.ts +14 -0
- package/dist/types/general.js +4 -0
- package/dist/types/image.d.ts +36 -0
- package/dist/types/image.js +7 -0
- package/dist/types/pipette.d.ts +1 -0
- package/dist/types/pipette.js +2 -0
- package/dist/utils/convert.d.ts +12 -0
- package/dist/utils/convert.js +27 -0
- package/dist/utils/filter.d.ts +16 -0
- package/dist/utils/filter.js +61 -0
- package/dist/web-component.d.ts +10 -0
- package/dist/web-component.js +60 -0
- package/package.json +30 -0
package/Readme.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# Lib
|
2
|
+
|
3
|
+
Canvas 2D library use: [`typescript`] [`canvas`];
|
4
|
+
|
5
|
+
For: [vue3] [native-js];
|
6
|
+
|
7
|
+
# Vue3 example
|
8
|
+
|
9
|
+
input:
|
10
|
+
```jsx
|
11
|
+
<script lang="ts" setup>
|
12
|
+
import { ref, onMounted } from 'vue';
|
13
|
+
import type { Ref } from 'vue';
|
14
|
+
|
15
|
+
import { VueCanvasEditorEngine, DrawService, ToolService, AppConfig } from 'sprite-creator'
|
16
|
+
import type { IDrawImageArgs } from 'sprite-creator/dist/types/image';
|
17
|
+
import ExecutionDelay from 'execution-delay';
|
18
|
+
|
19
|
+
const editor: Ref<HTMLElement | null> = ref(null);
|
20
|
+
|
21
|
+
AppConfig.CANVAS_SIZE.width = 700;
|
22
|
+
AppConfig.CANVAS_SIZE.height = 450;
|
23
|
+
const sc = new VueCanvasEditorEngine();
|
24
|
+
const initial = sc.getInitial();
|
25
|
+
customElements.define(initial.tag, initial.component);
|
26
|
+
|
27
|
+
const ctx: Ref<CanvasRenderingContext2D | null> = ref(null);
|
28
|
+
|
29
|
+
const quality: Ref<number> = ref(0);
|
30
|
+
const src: Ref<string | null> = ref(null);
|
31
|
+
|
32
|
+
onMounted(() => {
|
33
|
+
//@ts-ignore
|
34
|
+
editor.value?.addEventListener('get-editor-element', (e: CustomEvent) => {
|
35
|
+
const { editorElement, canvasSelector } = e.detail;
|
36
|
+
const canvas: HTMLCanvasElement = editorElement.querySelector(canvasSelector);
|
37
|
+
ctx.value = canvas.getContext("2d");
|
38
|
+
});
|
39
|
+
editor.value?.dispatchEvent(new Event('initial'));
|
40
|
+
});
|
41
|
+
|
42
|
+
function setImage(event: Event) {
|
43
|
+
const file: Ref<File | null> = ref(null);
|
44
|
+
const target = event.target as HTMLInputElement;
|
45
|
+
|
46
|
+
if (target && target.files) {
|
47
|
+
file.value = target.files[0];
|
48
|
+
}
|
49
|
+
|
50
|
+
if (!!file.value) {
|
51
|
+
src.value = window.URL.createObjectURL(file.value);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
function inputQuality(event: Event) {
|
56
|
+
const target = event.target as HTMLInputElement;
|
57
|
+
quality.value = +target.value;
|
58
|
+
ExecutionDelay.add('draw', () => draw(quality.value), 500);
|
59
|
+
}
|
60
|
+
|
61
|
+
function draw(qualityValue: number) {
|
62
|
+
console.log('qualityValue', qualityValue);
|
63
|
+
if (!!ctx.value && !!src.value) {
|
64
|
+
const options: IDrawImageArgs = {
|
65
|
+
position: {
|
66
|
+
x: 0,
|
67
|
+
y: 0,
|
68
|
+
}
|
69
|
+
};
|
70
|
+
DrawService.drawSmoothImage(ctx.value, src.value, options, { quality: qualityValue });
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
function takePipette() {
|
75
|
+
console.log('ToolService.registry', ToolService.registry);
|
76
|
+
const pipetteToolId = ToolService.registry.find((tool) => tool.name === "pipette")?.id;
|
77
|
+
if (pipetteToolId !== undefined) {
|
78
|
+
console.log('pipetteToolId');
|
79
|
+
ToolService.setActive(pipetteToolId);
|
80
|
+
}
|
81
|
+
}
|
82
|
+
</script>
|
83
|
+
|
84
|
+
<template>
|
85
|
+
<div class="editor">
|
86
|
+
<canvas-editor-engine class="editor" ref="editor">
|
87
|
+
<div slot="tools">
|
88
|
+
<div>
|
89
|
+
<input
|
90
|
+
id="Image"
|
91
|
+
class="editor__image-input_input"
|
92
|
+
name="image"
|
93
|
+
type="file"
|
94
|
+
accept="image/*"
|
95
|
+
@change="setImage"
|
96
|
+
capture
|
97
|
+
/>
|
98
|
+
</div>
|
99
|
+
<div>
|
100
|
+
<input type="range" name="quality" id="Quality" min="0" max="10" @change="inputQuality">
|
101
|
+
<span>Quality: {{ quality }}</span>
|
102
|
+
</div>
|
103
|
+
<button @click="takePipette">pipette</button>
|
104
|
+
</div>
|
105
|
+
</canvas-editor-engine>
|
106
|
+
</div>
|
107
|
+
</template>
|
108
|
+
```
|
109
|
+
|
110
|
+
simple output:
|
111
|
+
```jsx
|
112
|
+
<canvas-editor-engine>
|
113
|
+
#shadow-root (open)
|
114
|
+
<div>
|
115
|
+
<canvas id="sc-canvas"></canvas>
|
116
|
+
</div>
|
117
|
+
</canvas-editor-engine>
|
118
|
+
```
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { TSubscribeAction, TSubscriptionTypes } from "../types/canvas";
|
2
|
+
import { ICursorPosition, TCursorStyleName } from "../types/cursor";
|
3
|
+
import ComponentService from "../services/component.service";
|
4
|
+
export default class CanvasComponent extends ComponentService {
|
5
|
+
private static template;
|
6
|
+
private static css;
|
7
|
+
static eventListener: HTMLDivElement;
|
8
|
+
static canvas: HTMLCanvasElement;
|
9
|
+
static ctx: CanvasRenderingContext2D | null;
|
10
|
+
private static subscriptions;
|
11
|
+
private static _cursorStyle;
|
12
|
+
static getComponent(): {
|
13
|
+
canvasTemplate: HTMLElement;
|
14
|
+
canvasStyle: HTMLStyleElement;
|
15
|
+
};
|
16
|
+
static getCanvasSelector(): string;
|
17
|
+
static set cursorStyle(styleName: TCursorStyleName | undefined | null);
|
18
|
+
static getCursorPosition(event: MouseEvent): ICursorPosition;
|
19
|
+
static subscribe(eventName: TSubscriptionTypes, action: TSubscribeAction): void;
|
20
|
+
static simulateSubscriptions(): void;
|
21
|
+
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const config_1 = require("../config");
|
4
|
+
const component_service_1 = require("../services/component.service");
|
5
|
+
class CanvasComponent extends component_service_1.default {
|
6
|
+
static getComponent() {
|
7
|
+
const canvasTemplate = CanvasComponent.getTemplate(CanvasComponent.template);
|
8
|
+
const canvasStyle = CanvasComponent.getStyle(CanvasComponent.css);
|
9
|
+
CanvasComponent.canvas = canvasTemplate.getElementsByTagName('canvas')[0];
|
10
|
+
CanvasComponent.canvas.width = config_1.default.CANVAS_SIZE.width;
|
11
|
+
CanvasComponent.canvas.height = config_1.default.CANVAS_SIZE.height;
|
12
|
+
CanvasComponent.ctx = CanvasComponent.canvas.getContext("2d", { willReadFrequently: true });
|
13
|
+
CanvasComponent.eventListener = canvasTemplate.querySelector('#event-listener');
|
14
|
+
CanvasComponent.eventListener.style.width = config_1.default.CANVAS_SIZE.width + 'px';
|
15
|
+
CanvasComponent.eventListener.style.height = config_1.default.CANVAS_SIZE.height + 'px';
|
16
|
+
return { canvasTemplate, canvasStyle };
|
17
|
+
}
|
18
|
+
static getCanvasSelector() {
|
19
|
+
return '#sc-canvas';
|
20
|
+
}
|
21
|
+
static set cursorStyle(styleName) {
|
22
|
+
if (!!styleName) {
|
23
|
+
CanvasComponent._cursorStyle.before = CanvasComponent._cursorStyle.current;
|
24
|
+
CanvasComponent._cursorStyle.current = styleName;
|
25
|
+
CanvasComponent.eventListener.style.cursor = styleName;
|
26
|
+
}
|
27
|
+
else {
|
28
|
+
CanvasComponent.eventListener.style.cursor = 'default';
|
29
|
+
}
|
30
|
+
}
|
31
|
+
static getCursorPosition(event) {
|
32
|
+
const rect = CanvasComponent.canvas.getBoundingClientRect();
|
33
|
+
const x = event.clientX - rect.left;
|
34
|
+
const y = event.clientY - rect.top;
|
35
|
+
return { x, y };
|
36
|
+
}
|
37
|
+
static subscribe(eventName, action) {
|
38
|
+
CanvasComponent.subscriptions[eventName].push(action);
|
39
|
+
}
|
40
|
+
static simulateSubscriptions() {
|
41
|
+
const eventNames = Object.keys(CanvasComponent.subscriptions);
|
42
|
+
eventNames.forEach((eventName) => {
|
43
|
+
const actionsList = CanvasComponent.subscriptions[eventName];
|
44
|
+
if (!!actionsList.length) {
|
45
|
+
CanvasComponent.eventListener.addEventListener(eventName, (event) => {
|
46
|
+
const cursorPosition = CanvasComponent.getCursorPosition(event);
|
47
|
+
actionsList.forEach((action) => {
|
48
|
+
action(event, cursorPosition);
|
49
|
+
});
|
50
|
+
});
|
51
|
+
}
|
52
|
+
});
|
53
|
+
}
|
54
|
+
}
|
55
|
+
CanvasComponent.template = `
|
56
|
+
<div id="event-listener"></div>
|
57
|
+
<canvas id="sc-canvas"></canvas>
|
58
|
+
`;
|
59
|
+
CanvasComponent.css = `
|
60
|
+
#event-listener {
|
61
|
+
position: absolute;
|
62
|
+
z-index: 10000;
|
63
|
+
}
|
64
|
+
`;
|
65
|
+
CanvasComponent.subscriptions = {
|
66
|
+
click: [],
|
67
|
+
mousemove: [],
|
68
|
+
mousedown: [],
|
69
|
+
mouseup: [],
|
70
|
+
};
|
71
|
+
CanvasComponent._cursorStyle = {
|
72
|
+
before: null,
|
73
|
+
current: 'default',
|
74
|
+
};
|
75
|
+
exports.default = CanvasComponent;
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import ComponentService from "../services/component.service";
|
2
|
+
import type { IExcretionsCoords, TExcretionToolState } from "../types/excretion";
|
3
|
+
export default class ExcretionsComponent extends ComponentService {
|
4
|
+
private static template;
|
5
|
+
private static css;
|
6
|
+
static excretionWrap: HTMLElement;
|
7
|
+
private static _excretions;
|
8
|
+
private static _excretionState;
|
9
|
+
private static _excretionActivity;
|
10
|
+
private static _excretionToolState;
|
11
|
+
private static _tempCoords;
|
12
|
+
static excretionsCoords: IExcretionsCoords[];
|
13
|
+
private static tool;
|
14
|
+
static getComponent(): {
|
15
|
+
excretionsTemplate: HTMLElement;
|
16
|
+
excretionsStyle: HTMLStyleElement;
|
17
|
+
};
|
18
|
+
private static set excretionState(value);
|
19
|
+
static setToolState(toolState: TExcretionToolState): void;
|
20
|
+
static clearExcretionsCoords(): void;
|
21
|
+
private static getTempCoords;
|
22
|
+
private static endExcretion;
|
23
|
+
private static emmit;
|
24
|
+
}
|
@@ -0,0 +1,192 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const component_service_1 = require("../services/component.service");
|
4
|
+
const tool_service_1 = require("../services/tool.service");
|
5
|
+
const canvas_component_1 = require("./canvas.component");
|
6
|
+
class ExcretionsComponent extends component_service_1.default {
|
7
|
+
static getComponent() {
|
8
|
+
const wrapOptions = {
|
9
|
+
className: 'excretions-wrap',
|
10
|
+
};
|
11
|
+
const excretionsTemplate = ExcretionsComponent.getTemplate(ExcretionsComponent.template, wrapOptions);
|
12
|
+
const excretionsStyle = ExcretionsComponent.getStyle(ExcretionsComponent.css);
|
13
|
+
ExcretionsComponent.excretionWrap = excretionsTemplate;
|
14
|
+
ExcretionsComponent.emmit();
|
15
|
+
return { excretionsTemplate, excretionsStyle };
|
16
|
+
}
|
17
|
+
static set excretionState(state) {
|
18
|
+
ExcretionsComponent._excretionState = state;
|
19
|
+
switch (state) {
|
20
|
+
case 'abandoned':
|
21
|
+
canvas_component_1.default.cursorStyle = 'default';
|
22
|
+
break;
|
23
|
+
case 'create':
|
24
|
+
canvas_component_1.default.cursorStyle = 'crosshair';
|
25
|
+
break;
|
26
|
+
case 'add':
|
27
|
+
canvas_component_1.default.cursorStyle = 'copy';
|
28
|
+
break;
|
29
|
+
case 'remove':
|
30
|
+
canvas_component_1.default.cursorStyle = 'alias';
|
31
|
+
break;
|
32
|
+
default:
|
33
|
+
canvas_component_1.default.cursorStyle = 'default';
|
34
|
+
break;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
static setToolState(toolState) {
|
38
|
+
ExcretionsComponent._excretionToolState = toolState;
|
39
|
+
switch (toolState) {
|
40
|
+
case 'abandoned':
|
41
|
+
ExcretionsComponent.excretionState = 'abandoned';
|
42
|
+
ExcretionsComponent._excretionActivity = 'abandoned';
|
43
|
+
break;
|
44
|
+
case 'taken':
|
45
|
+
ExcretionsComponent.excretionState = 'create';
|
46
|
+
break;
|
47
|
+
default:
|
48
|
+
ExcretionsComponent.excretionState = 'abandoned';
|
49
|
+
ExcretionsComponent._excretionActivity = 'abandoned';
|
50
|
+
break;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
static clearExcretionsCoords() {
|
54
|
+
console.log('clear!');
|
55
|
+
ExcretionsComponent._excretions.forEach((excretion) => excretion.remove());
|
56
|
+
ExcretionsComponent._excretions = [];
|
57
|
+
ExcretionsComponent.excretionsCoords = [];
|
58
|
+
}
|
59
|
+
static getTempCoords() {
|
60
|
+
const startCoords = ExcretionsComponent._tempCoords[0];
|
61
|
+
const endCoords = ExcretionsComponent._tempCoords[1];
|
62
|
+
const coords = Object.assign(startCoords, endCoords);
|
63
|
+
ExcretionsComponent._tempCoords = [];
|
64
|
+
return coords;
|
65
|
+
}
|
66
|
+
static endExcretion() {
|
67
|
+
const coords = ExcretionsComponent.getTempCoords();
|
68
|
+
ExcretionsComponent.excretionsCoords.push(coords);
|
69
|
+
ExcretionsComponent._excretionActivity = 'end';
|
70
|
+
console.log('ExcretionsComponent.excretionsCoords', ExcretionsComponent.excretionsCoords);
|
71
|
+
}
|
72
|
+
static emmit() {
|
73
|
+
canvas_component_1.default.subscribe('mousedown', (event, cursorPosition) => {
|
74
|
+
const toolState = ExcretionsComponent._excretionToolState;
|
75
|
+
if (toolState === 'abandoned')
|
76
|
+
return;
|
77
|
+
const state = ExcretionsComponent._excretionState;
|
78
|
+
if (state === 'create') {
|
79
|
+
const wrapOptions = {
|
80
|
+
className: 'excretion',
|
81
|
+
};
|
82
|
+
const excretionTemplate = ExcretionsComponent.getTemplate('', wrapOptions);
|
83
|
+
ExcretionsComponent.clearExcretionsCoords();
|
84
|
+
const tempStart = {
|
85
|
+
start: cursorPosition,
|
86
|
+
};
|
87
|
+
excretionTemplate.style.left = `${tempStart.start.x}px`;
|
88
|
+
excretionTemplate.style.top = `${tempStart.start.y}px`;
|
89
|
+
const excretionElement = ExcretionsComponent.excretionWrap.appendChild(excretionTemplate);
|
90
|
+
ExcretionsComponent._excretions.push(excretionElement);
|
91
|
+
ExcretionsComponent._tempCoords.push(tempStart);
|
92
|
+
}
|
93
|
+
if (state === 'add') {
|
94
|
+
const tempStart = {
|
95
|
+
start: cursorPosition,
|
96
|
+
};
|
97
|
+
ExcretionsComponent._tempCoords.push(tempStart);
|
98
|
+
}
|
99
|
+
ExcretionsComponent._excretionActivity = 'active';
|
100
|
+
});
|
101
|
+
canvas_component_1.default.subscribe('mousemove', (event, cursorPosition) => {
|
102
|
+
const toolState = ExcretionsComponent._excretionToolState;
|
103
|
+
if (toolState === 'abandoned')
|
104
|
+
return;
|
105
|
+
const activity = ExcretionsComponent._excretionActivity;
|
106
|
+
if (event.altKey && ExcretionsComponent._excretionState !== 'abandoned') {
|
107
|
+
ExcretionsComponent._excretionState = 'add';
|
108
|
+
}
|
109
|
+
if (activity === 'abandoned')
|
110
|
+
return;
|
111
|
+
if (activity === 'active') {
|
112
|
+
const excretionLastIndex = ExcretionsComponent._excretions.length - 1;
|
113
|
+
const excretion = ExcretionsComponent._excretions[excretionLastIndex];
|
114
|
+
const excretionX = +(excretion.style.left.split('px')[0]);
|
115
|
+
const excretionY = +(excretion.style.top.split('px')[0]);
|
116
|
+
const width = Math.abs(cursorPosition.x - excretionX);
|
117
|
+
const height = Math.abs(cursorPosition.y - excretionY);
|
118
|
+
excretion.style.width = width + 'px';
|
119
|
+
excretion.style.height = height + 'px';
|
120
|
+
const isRightBottom = cursorPosition.x > excretionX && cursorPosition.y > excretionY;
|
121
|
+
const isLeftBottom = cursorPosition.x < excretionX && cursorPosition.y > excretionY;
|
122
|
+
const isLeftTop = cursorPosition.x < excretionX && cursorPosition.y < excretionY;
|
123
|
+
const isRightTop = cursorPosition.x > excretionX && cursorPosition.y < excretionY;
|
124
|
+
if (isRightBottom) {
|
125
|
+
excretion.style.transform = `translateX(0px) translateY(0px)`;
|
126
|
+
}
|
127
|
+
else if (isLeftBottom) {
|
128
|
+
excretion.style.transform = `translateX(-${width}px) translateY(0px)`;
|
129
|
+
}
|
130
|
+
else if (isLeftTop) {
|
131
|
+
excretion.style.transform = `translateX(-${width}px) translateY(-${height}px)`;
|
132
|
+
}
|
133
|
+
else if (isRightTop) {
|
134
|
+
excretion.style.transform = `translateX(0px) translateY(-${height}px)`;
|
135
|
+
}
|
136
|
+
}
|
137
|
+
});
|
138
|
+
canvas_component_1.default.subscribe('mouseup', (event, cursorPosition) => {
|
139
|
+
const toolState = ExcretionsComponent._excretionToolState;
|
140
|
+
if (toolState === 'abandoned')
|
141
|
+
return;
|
142
|
+
const state = ExcretionsComponent._excretionState;
|
143
|
+
if (state === 'abandoned')
|
144
|
+
return;
|
145
|
+
if (state === 'create' || state === 'add') {
|
146
|
+
const tempEnd = {
|
147
|
+
end: cursorPosition,
|
148
|
+
};
|
149
|
+
ExcretionsComponent._tempCoords.push(tempEnd);
|
150
|
+
ExcretionsComponent.endExcretion();
|
151
|
+
}
|
152
|
+
});
|
153
|
+
}
|
154
|
+
}
|
155
|
+
ExcretionsComponent.template = ``;
|
156
|
+
ExcretionsComponent.css = `
|
157
|
+
.excretion {
|
158
|
+
display: flex;
|
159
|
+
position: absolute;
|
160
|
+
background-image: linear-gradient(90deg, silver 50%, transparent 50%), linear-gradient(90deg, silver 50%, transparent 50%), linear-gradient(0deg, silver 50%, transparent 50%), linear-gradient(0deg, silver 50%, transparent 50%);
|
161
|
+
background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
|
162
|
+
background-size: 8px 1px, 8px 1px, 1px 8px, 1px 8px;
|
163
|
+
background-position: left top, right bottom, left bottom, right top;
|
164
|
+
animation: border-dance 1s infinite linear;
|
165
|
+
}
|
166
|
+
|
167
|
+
@keyframes border-dance {
|
168
|
+
0% {
|
169
|
+
background-position: left top, right bottom, left bottom, right top;
|
170
|
+
}
|
171
|
+
100% {
|
172
|
+
background-position: left 8px top, right 8px bottom, left bottom 8px, right top 8px;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
`;
|
176
|
+
ExcretionsComponent._excretions = [];
|
177
|
+
ExcretionsComponent._excretionState = 'abandoned';
|
178
|
+
ExcretionsComponent._excretionActivity = 'abandoned';
|
179
|
+
ExcretionsComponent._excretionToolState = 'abandoned';
|
180
|
+
ExcretionsComponent._tempCoords = [];
|
181
|
+
ExcretionsComponent.excretionsCoords = [];
|
182
|
+
ExcretionsComponent.tool = {
|
183
|
+
id: 1,
|
184
|
+
name: 'excretion',
|
185
|
+
onAction: () => ExcretionsComponent.setToolState('taken'),
|
186
|
+
offAction: () => ExcretionsComponent.setToolState('abandoned'),
|
187
|
+
support: () => ExcretionsComponent.clearExcretionsCoords(),
|
188
|
+
};
|
189
|
+
(() => {
|
190
|
+
tool_service_1.default.add(ExcretionsComponent.tool);
|
191
|
+
})();
|
192
|
+
exports.default = ExcretionsComponent;
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import { TPipetteState } from "../types/pipette";
|
2
|
+
import { THEXColor } from "../types/general";
|
3
|
+
import ComponentService from "../services/component.service";
|
4
|
+
export default class PipetteComponent extends ComponentService {
|
5
|
+
static template: string;
|
6
|
+
static css: string;
|
7
|
+
static pipette: HTMLElement;
|
8
|
+
private static _pipetteColor;
|
9
|
+
static set pipetteColor(color: THEXColor);
|
10
|
+
static get pipetteColor(): THEXColor;
|
11
|
+
private static _pipetteColorElement;
|
12
|
+
private static _pipetteState;
|
13
|
+
private static tool;
|
14
|
+
static getComponent(): {
|
15
|
+
pipetteTemplate: HTMLElement;
|
16
|
+
pipetteStyle: HTMLStyleElement;
|
17
|
+
};
|
18
|
+
static setState(state: TPipetteState): void;
|
19
|
+
static emmit(): void;
|
20
|
+
private static setColorFromChoosenPixel;
|
21
|
+
private static show;
|
22
|
+
private static hide;
|
23
|
+
}
|
@@ -0,0 +1,138 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const convert_1 = require("../utils/convert");
|
4
|
+
const canvas_component_1 = require("./canvas.component");
|
5
|
+
const component_service_1 = require("../services/component.service");
|
6
|
+
const tool_service_1 = require("../services/tool.service");
|
7
|
+
class PipetteComponent extends component_service_1.default {
|
8
|
+
static set pipetteColor(color) {
|
9
|
+
PipetteComponent._pipetteColor = color;
|
10
|
+
PipetteComponent._pipetteColorElement.style.borderColor = PipetteComponent._pipetteColor;
|
11
|
+
}
|
12
|
+
static get pipetteColor() {
|
13
|
+
return PipetteComponent._pipetteColor;
|
14
|
+
}
|
15
|
+
static getComponent() {
|
16
|
+
const wrapOptions = {
|
17
|
+
className: 'pipette',
|
18
|
+
};
|
19
|
+
const pipetteTemplate = PipetteComponent.getTemplate(PipetteComponent.template, wrapOptions);
|
20
|
+
const pipetteStyle = PipetteComponent.getStyle(PipetteComponent.css);
|
21
|
+
PipetteComponent.pipette = pipetteTemplate;
|
22
|
+
PipetteComponent._pipetteColorElement = pipetteTemplate.querySelector('.pipette_color');
|
23
|
+
PipetteComponent.emmit();
|
24
|
+
return { pipetteTemplate, pipetteStyle };
|
25
|
+
}
|
26
|
+
static setState(state) {
|
27
|
+
PipetteComponent._pipetteState = state;
|
28
|
+
switch (state) {
|
29
|
+
case 'abandoned':
|
30
|
+
return PipetteComponent.hide();
|
31
|
+
case 'taken':
|
32
|
+
return PipetteComponent.show();
|
33
|
+
case 'selected-color':
|
34
|
+
return PipetteComponent.show();
|
35
|
+
default:
|
36
|
+
return PipetteComponent.hide();
|
37
|
+
}
|
38
|
+
}
|
39
|
+
static emmit() {
|
40
|
+
canvas_component_1.default.subscribe('mousemove', (event, cursorPosition) => {
|
41
|
+
const state = PipetteComponent._pipetteState;
|
42
|
+
if (state === 'taken' || state === 'selected-color') {
|
43
|
+
const { x, y } = cursorPosition;
|
44
|
+
PipetteComponent.pipette.style.left = `${x + 10}px`;
|
45
|
+
PipetteComponent.pipette.style.top = `${y + 10}px`;
|
46
|
+
}
|
47
|
+
});
|
48
|
+
canvas_component_1.default.subscribe('click', (event, cursorPosition) => {
|
49
|
+
const state = PipetteComponent._pipetteState;
|
50
|
+
if (state === 'taken' || state === 'selected-color') {
|
51
|
+
console.log('pipetteState', state);
|
52
|
+
if (state === 'taken') {
|
53
|
+
PipetteComponent.setColorFromChoosenPixel(cursorPosition);
|
54
|
+
PipetteComponent.setState('selected-color');
|
55
|
+
}
|
56
|
+
if (state === 'selected-color') {
|
57
|
+
PipetteComponent.setColorFromChoosenPixel(cursorPosition);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
});
|
61
|
+
}
|
62
|
+
static setColorFromChoosenPixel(cursorPosition) {
|
63
|
+
const { x, y } = cursorPosition;
|
64
|
+
const pixel = canvas_component_1.default.ctx.getImageData(x, y, 1, 1).data;
|
65
|
+
const hexPixel = convert_1.Convert.rgbToHex(pixel[0], pixel[1], pixel[2]);
|
66
|
+
PipetteComponent.pipetteColor = hexPixel;
|
67
|
+
}
|
68
|
+
static show() {
|
69
|
+
PipetteComponent.pipette.style.display = 'flex';
|
70
|
+
canvas_component_1.default.cursorStyle = 'default';
|
71
|
+
}
|
72
|
+
static hide() {
|
73
|
+
PipetteComponent.pipette.style.display = 'none';
|
74
|
+
canvas_component_1.default.cursorStyle = 'default';
|
75
|
+
}
|
76
|
+
}
|
77
|
+
PipetteComponent.template = `
|
78
|
+
<div class="pipette_border-out">
|
79
|
+
<div class="pipette_color">
|
80
|
+
<div class="pipette_border-in">
|
81
|
+
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M17 12C17 14.7614 14.7614 17 12 17M17 12C17 9.23858 14.7614 7 12 7M17 12H19M12 17C9.23858 17 7 14.7614 7 12M12 17V19M7 12C7 9.23858 9.23858 7 12 7M7 12H5M12 7V5M14 12C14 13.1046 13.1046 14 12 14C10.8954 14 10 13.1046 10 12C10 10.8954 10.8954 10 12 10C13.1046 10 14 10.8954 14 12Z" stroke="#d9d9d9" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
|
82
|
+
</div>
|
83
|
+
</div>
|
84
|
+
</div>
|
85
|
+
`;
|
86
|
+
PipetteComponent.css = `
|
87
|
+
.pipette {
|
88
|
+
position: absolute;
|
89
|
+
display: none;
|
90
|
+
justify-content: center;
|
91
|
+
align-items: center;
|
92
|
+
width: 48px;
|
93
|
+
height: 48px;
|
94
|
+
}
|
95
|
+
|
96
|
+
.pipette_border-out {
|
97
|
+
display: flex;
|
98
|
+
justify-content: center;
|
99
|
+
align-items: center;
|
100
|
+
border-radius: 100px;
|
101
|
+
border: solid 2px #d9d9d9;
|
102
|
+
width: 44px;
|
103
|
+
height: 44px;
|
104
|
+
}
|
105
|
+
|
106
|
+
.pipette_border-in {
|
107
|
+
display: flex;
|
108
|
+
justify-content: center;
|
109
|
+
align-items: center;
|
110
|
+
border-radius: 100px;
|
111
|
+
border: solid 1px #d9d9d9;
|
112
|
+
width: 32px;
|
113
|
+
height: 32px;
|
114
|
+
}
|
115
|
+
|
116
|
+
.pipette_color {
|
117
|
+
display: flex;
|
118
|
+
justify-content: center;
|
119
|
+
align-items: center;
|
120
|
+
width: 34px;
|
121
|
+
height: 34px;
|
122
|
+
border-radius: 100px;
|
123
|
+
border-color: blue;
|
124
|
+
border-style: solid;
|
125
|
+
border-width: 5px;
|
126
|
+
}
|
127
|
+
`;
|
128
|
+
PipetteComponent._pipetteState = 'abandoned';
|
129
|
+
PipetteComponent.tool = {
|
130
|
+
id: 0,
|
131
|
+
name: 'pipette',
|
132
|
+
onAction: () => PipetteComponent.setState('taken'),
|
133
|
+
offAction: () => PipetteComponent.setState('abandoned'),
|
134
|
+
};
|
135
|
+
(() => {
|
136
|
+
tool_service_1.default.add(PipetteComponent.tool);
|
137
|
+
})();
|
138
|
+
exports.default = PipetteComponent;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import ComponentService from "../services/component.service";
|
2
|
+
export default class SlotComponent extends ComponentService {
|
3
|
+
private static template;
|
4
|
+
private static css;
|
5
|
+
static slot: HTMLSlotElement;
|
6
|
+
static getComponent(slotName: string): {
|
7
|
+
slotTemplate: HTMLElement;
|
8
|
+
slotStyle: HTMLStyleElement;
|
9
|
+
};
|
10
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const component_service_1 = require("../services/component.service");
|
4
|
+
class SlotComponent extends component_service_1.default {
|
5
|
+
static getComponent(slotName) {
|
6
|
+
const wrapOptions = {
|
7
|
+
className: 'slot-wrapper',
|
8
|
+
};
|
9
|
+
const slotTemplate = SlotComponent.getTemplate(SlotComponent.template, wrapOptions);
|
10
|
+
const slotStyle = SlotComponent.getStyle(SlotComponent.css);
|
11
|
+
SlotComponent.slot = slotTemplate.querySelector('slot');
|
12
|
+
SlotComponent.slot.name = slotName;
|
13
|
+
return { slotTemplate, slotStyle };
|
14
|
+
}
|
15
|
+
}
|
16
|
+
SlotComponent.template = `
|
17
|
+
<slot class="slot"></slot>
|
18
|
+
`;
|
19
|
+
SlotComponent.css = ``;
|
20
|
+
exports.default = SlotComponent;
|
package/dist/config.d.ts
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
import { ICanvasSize } from "./types/canvas";
|
2
|
+
export default class AppConfig {
|
3
|
+
private static _WEB_COMPONENT_TAG_NAME;
|
4
|
+
private static _CANVAS_SIZE;
|
5
|
+
static get WEB_COMPONENT_TAG_NAME(): string;
|
6
|
+
static set WEB_COMPONENT_TAG_NAME(value: string | undefined);
|
7
|
+
static get CANVAS_SIZE(): ICanvasSize;
|
8
|
+
static set CANVAS_SIZE(value: ICanvasSize | undefined);
|
9
|
+
}
|
package/dist/config.js
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
class AppConfig {
|
4
|
+
static get WEB_COMPONENT_TAG_NAME() {
|
5
|
+
return AppConfig._WEB_COMPONENT_TAG_NAME;
|
6
|
+
}
|
7
|
+
static set WEB_COMPONENT_TAG_NAME(value) {
|
8
|
+
if (!!value && typeof value === 'string') {
|
9
|
+
AppConfig._WEB_COMPONENT_TAG_NAME = value;
|
10
|
+
}
|
11
|
+
}
|
12
|
+
static get CANVAS_SIZE() {
|
13
|
+
return AppConfig._CANVAS_SIZE;
|
14
|
+
}
|
15
|
+
static set CANVAS_SIZE(value) {
|
16
|
+
if (!!value && !!(value === null || value === void 0 ? void 0 : value.width) && !!(value === null || value === void 0 ? void 0 : value.height)) {
|
17
|
+
AppConfig._CANVAS_SIZE = value;
|
18
|
+
}
|
19
|
+
else {
|
20
|
+
console.warn('CANVAS_SIZE denied');
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
AppConfig._WEB_COMPONENT_TAG_NAME = 'canvas-editor-engine';
|
25
|
+
AppConfig._CANVAS_SIZE = {
|
26
|
+
width: 300,
|
27
|
+
height: 150,
|
28
|
+
};
|
29
|
+
exports.default = AppConfig;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import type { IFilterOptions, IImageOptions, TFilterMethod } from "../../types/image";
|
2
|
+
import { Filter } from "../../utils/filter";
|
3
|
+
export default class VagueFilter extends Filter {
|
4
|
+
options: IImageOptions;
|
5
|
+
filterList: TFilterMethod[];
|
6
|
+
constructor(ctx: CanvasRenderingContext2D, options: IImageOptions);
|
7
|
+
on(action: TFilterMethod, filterOptions: IFilterOptions): void;
|
8
|
+
pixel(imageData: ImageData, filterOptions: IFilterOptions): ImageData;
|
9
|
+
private getQualityBuff;
|
10
|
+
private getMostCommonQuanlityBuff;
|
11
|
+
private getMostCommonElement;
|
12
|
+
}
|