@visns-studio/visns-components 5.0.19 → 5.0.20
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/package.json +6 -6
- package/src/components/crm/MultiSelect.jsx +46 -67
- package/src/components/crm/auth/styles/Profile.module.scss +6 -7
- package/src/components/crm/generic/GenericDashboard.jsx +467 -29
- package/src/components/crm/generic/GenericFormBuilder.jsx +96 -32
- package/src/components/crm/generic/styles/AuditLog.module.scss +3 -3
- package/src/components/crm/generic/styles/AuditLogs.module.scss +1 -1
- package/src/components/crm/generic/styles/GenericDashboard.module.scss +364 -0
- package/src/components/crm/generic/styles/GenericDynamic.module.scss +11 -11
- package/src/components/crm/generic/styles/GenericFormBuilder.module.scss +327 -317
- package/src/components/crm/generic/styles/GenericIndex.module.scss +8 -8
- package/src/components/crm/generic/styles/GenericSort.module.scss +3 -3
- package/src/components/crm/generic/styles/NotificationList.module.scss +2 -2
- package/src/components/crm/sketch/SketchField.jsx +395 -0
- package/src/components/crm/sketch/arrow.jsx +108 -0
- package/src/components/crm/sketch/circle.jsx +75 -0
- package/src/components/crm/sketch/default-tool.jsx +16 -0
- package/src/components/crm/sketch/fabrictool.jsx +22 -0
- package/src/components/crm/sketch/history.jsx +144 -0
- package/src/components/crm/sketch/json/config.json +14 -0
- package/src/components/crm/sketch/line.jsx +64 -0
- package/src/components/crm/sketch/pan.jsx +48 -0
- package/src/components/crm/sketch/pencil.jsx +36 -0
- package/src/components/crm/sketch/rectangle-label-object.jsx +69 -0
- package/src/components/crm/sketch/rectangle-label.jsx +93 -0
- package/src/components/crm/sketch/rectangle.jsx +76 -0
- package/src/components/crm/sketch/select.jsx +16 -0
- package/src/components/crm/sketch/tools.jsx +11 -0
- package/src/components/crm/sketch/utils.jsx +67 -0
- package/src/components/crm/sorting/Item.jsx +2 -2
- package/src/components/crm/sorting/styles/Item.module.scss +12 -65
- package/src/components/crm/sorting/styles/List.module.scss +6 -20
- package/src/components/crm/styles/Form.module.scss +4 -6
- package/src/components/crm/styles/MultiSelect.module.scss +4 -0
- package/src/components/crm/styles/Navigation.module.scss +13 -6
- package/src/components/crm/styles/QrCode.module.scss +2 -2
- package/src/components/styles/global.css +8 -0
- package/src/index.js +2 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* eslint no-unused-vars: 0 */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* "Abstract" like base class for a Canvas tool
|
|
5
|
+
*/
|
|
6
|
+
class FabricCanvasTool {
|
|
7
|
+
constructor(canvas) {
|
|
8
|
+
this._canvas = canvas;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
configureCanvas(props) {}
|
|
12
|
+
|
|
13
|
+
doMouseUp(event) {}
|
|
14
|
+
|
|
15
|
+
doMouseDown(event) {}
|
|
16
|
+
|
|
17
|
+
doMouseMove(event) {}
|
|
18
|
+
|
|
19
|
+
doMouseOut(event) {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default FabricCanvasTool;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maintains the history of an object
|
|
3
|
+
*/
|
|
4
|
+
class History {
|
|
5
|
+
constructor(undoLimit = 10, debug = false) {
|
|
6
|
+
this.undoLimit = undoLimit;
|
|
7
|
+
this.undoList = [];
|
|
8
|
+
this.redoList = [];
|
|
9
|
+
this.current = null;
|
|
10
|
+
this.debug = debug;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get the limit of undo/redo actions
|
|
15
|
+
*
|
|
16
|
+
* @returns {number|*} the undo limit, as it is configured when constructing the history instance
|
|
17
|
+
*/
|
|
18
|
+
getUndoLimit() {
|
|
19
|
+
return this.undoLimit;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get Current state
|
|
24
|
+
*
|
|
25
|
+
* @returns {null|*}
|
|
26
|
+
*/
|
|
27
|
+
getCurrent() {
|
|
28
|
+
return this.current;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Keep an object to history
|
|
33
|
+
*
|
|
34
|
+
* This method will set the object as current value and will push the previous "current" object to the undo history
|
|
35
|
+
*
|
|
36
|
+
* @param obj
|
|
37
|
+
*/
|
|
38
|
+
keep(obj) {
|
|
39
|
+
try {
|
|
40
|
+
if (
|
|
41
|
+
this.current &&
|
|
42
|
+
JSON.stringify(this.current) === JSON.stringify(obj)
|
|
43
|
+
) {
|
|
44
|
+
return; // Skip if no meaningful change
|
|
45
|
+
}
|
|
46
|
+
this.redoList = []; // Clear redo list on new action
|
|
47
|
+
if (this.current) {
|
|
48
|
+
this.undoList.push(this.current); // Store previous state in undo list
|
|
49
|
+
}
|
|
50
|
+
if (this.undoList.length > this.undoLimit) {
|
|
51
|
+
this.undoList.shift(); // Maintain limit on history size
|
|
52
|
+
}
|
|
53
|
+
this.current = obj; // Update current state
|
|
54
|
+
} finally {
|
|
55
|
+
this.print();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Undo the last object, this operation will set the current object to one step back in time
|
|
61
|
+
*
|
|
62
|
+
* @returns the new current value after the undo operation, else null if no undo operation was possible
|
|
63
|
+
*/
|
|
64
|
+
undo() {
|
|
65
|
+
try {
|
|
66
|
+
if (this.current) {
|
|
67
|
+
this.redoList.push(this.current);
|
|
68
|
+
if (this.redoList.length > this.undoLimit) {
|
|
69
|
+
this.redoList.shift();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (this.undoList.length > 0) {
|
|
74
|
+
this.current = this.undoList.pop();
|
|
75
|
+
return this.current;
|
|
76
|
+
} else {
|
|
77
|
+
// If no more states left in undoList, set current to null (clear canvas)
|
|
78
|
+
this.current = null;
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
} finally {
|
|
82
|
+
this.print();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Redo the last object, redo happens only if no keep operations have been performed
|
|
88
|
+
*
|
|
89
|
+
* @returns the new current value after the redo operation, or null if no redo operation was possible
|
|
90
|
+
*/
|
|
91
|
+
redo() {
|
|
92
|
+
try {
|
|
93
|
+
if (this.redoList.length > 0) {
|
|
94
|
+
if (this.current) this.undoList.push(this.current);
|
|
95
|
+
this.current = this.redoList.pop();
|
|
96
|
+
return this.current;
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
} finally {
|
|
100
|
+
this.print();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Checks whether we can perform a redo operation
|
|
106
|
+
*
|
|
107
|
+
* @returns {boolean}
|
|
108
|
+
*/
|
|
109
|
+
canRedo() {
|
|
110
|
+
return this.redoList.length > 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Checks whether we can perform an undo operation
|
|
115
|
+
*
|
|
116
|
+
* @returns {boolean}
|
|
117
|
+
*/
|
|
118
|
+
canUndo() {
|
|
119
|
+
return this.undoList.length > 0 || this.current !== null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Clears the history maintained, can be undone
|
|
124
|
+
*/
|
|
125
|
+
clear() {
|
|
126
|
+
this.undoList = [];
|
|
127
|
+
this.redoList = [];
|
|
128
|
+
this.current = null;
|
|
129
|
+
this.print();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
print() {
|
|
133
|
+
if (this.debug) {
|
|
134
|
+
/* eslint-disable no-console */
|
|
135
|
+
console.log(
|
|
136
|
+
this.undoList,
|
|
137
|
+
' -> ' + this.current + ' <- ',
|
|
138
|
+
this.redoList.slice(0).reverse()
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export default History;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"canvasTypes": [
|
|
3
|
+
{
|
|
4
|
+
"id": "humanBody",
|
|
5
|
+
"label": "Human Body",
|
|
6
|
+
"url": "https://d16lktya8ojp5z.cloudfront.net/adelphi/images/body-diagram.png"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"id": "car",
|
|
10
|
+
"label": "Car",
|
|
11
|
+
"url": "https://d16lktya8ojp5z.cloudfront.net/adelphi/images/car-diagram.png"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import FabricCanvasTool from './fabrictool';
|
|
2
|
+
import { Line as FabricLine } from 'fabric';
|
|
3
|
+
|
|
4
|
+
class Line extends FabricCanvasTool {
|
|
5
|
+
constructor(canvas) {
|
|
6
|
+
super(canvas);
|
|
7
|
+
// Define event handlers as arrow functions for consistent references
|
|
8
|
+
this.doMouseDown = (o) => this._doMouseDown(o);
|
|
9
|
+
this.doMouseMove = (o) => this._doMouseMove(o);
|
|
10
|
+
this.doMouseUp = () => this._doMouseUp();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
configureCanvas(props) {
|
|
14
|
+
const canvas = this._canvas;
|
|
15
|
+
canvas.isDrawingMode = false; // Disable drawing mode for custom drawing
|
|
16
|
+
canvas.selection = false;
|
|
17
|
+
this._width = props.lineWidth || 2;
|
|
18
|
+
this._color = props.lineColor || 'black';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
attachListeners() {
|
|
22
|
+
this._canvas.on('mouse:down', this.doMouseDown);
|
|
23
|
+
this._canvas.on('mouse:move', this.doMouseMove);
|
|
24
|
+
this._canvas.on('mouse:up', this.doMouseUp);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
detachListeners() {
|
|
28
|
+
this._canvas.off('mouse:down', this.doMouseDown);
|
|
29
|
+
this._canvas.off('mouse:move', this.doMouseMove);
|
|
30
|
+
this._canvas.off('mouse:up', this.doMouseUp);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_doMouseDown(o) {
|
|
34
|
+
this.isDown = true;
|
|
35
|
+
const canvas = this._canvas;
|
|
36
|
+
const pointer = canvas.getPointer(o.e);
|
|
37
|
+
const points = [pointer.x, pointer.y, pointer.x, pointer.y];
|
|
38
|
+
|
|
39
|
+
this.line = new FabricLine(points, {
|
|
40
|
+
strokeWidth: this._width,
|
|
41
|
+
stroke: this._color,
|
|
42
|
+
originX: 'center',
|
|
43
|
+
originY: 'center',
|
|
44
|
+
selectable: false,
|
|
45
|
+
evented: false,
|
|
46
|
+
});
|
|
47
|
+
canvas.add(this.line);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
_doMouseMove(o) {
|
|
51
|
+
if (!this.isDown) return;
|
|
52
|
+
const canvas = this._canvas;
|
|
53
|
+
const pointer = canvas.getPointer(o.e);
|
|
54
|
+
this.line.set({ x2: pointer.x, y2: pointer.y });
|
|
55
|
+
this.line.setCoords();
|
|
56
|
+
canvas.renderAll();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
_doMouseUp() {
|
|
60
|
+
this.isDown = false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default Line;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import FabricCanvasTool from './fabrictool';
|
|
2
|
+
import * as fabric from 'fabric'; // v6
|
|
3
|
+
|
|
4
|
+
class Pan extends FabricCanvasTool {
|
|
5
|
+
configureCanvas(props) {
|
|
6
|
+
const canvas = this._canvas;
|
|
7
|
+
canvas.isDrawingMode = false;
|
|
8
|
+
canvas.selection = false;
|
|
9
|
+
canvas.forEachObject((o) => {
|
|
10
|
+
o.selectable = false;
|
|
11
|
+
o.evented = false;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Change cursor to move
|
|
15
|
+
canvas.defaultCursor = 'move';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
doMouseDown(o) {
|
|
19
|
+
const canvas = this._canvas;
|
|
20
|
+
this.isDown = true;
|
|
21
|
+
const pointer = canvas.getPointer(o.e);
|
|
22
|
+
this.startX = pointer.x;
|
|
23
|
+
this.startY = pointer.y;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
doMouseMove(o) {
|
|
27
|
+
if (!this.isDown) return;
|
|
28
|
+
const canvas = this._canvas;
|
|
29
|
+
const pointer = canvas.getPointer(o.e);
|
|
30
|
+
|
|
31
|
+
// Pan the canvas based on pointer movement
|
|
32
|
+
canvas.relativePan({
|
|
33
|
+
x: pointer.x - this.startX,
|
|
34
|
+
y: pointer.y - this.startY,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Update the initial positions for consistent panning
|
|
38
|
+
this.startX = pointer.x;
|
|
39
|
+
this.startY = pointer.y;
|
|
40
|
+
canvas.requestRenderAll();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
doMouseUp() {
|
|
44
|
+
this.isDown = false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default Pan;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import FabricCanvasTool from './fabrictool';
|
|
2
|
+
import * as fabric from 'fabric'; // v6
|
|
3
|
+
|
|
4
|
+
class Pencil extends FabricCanvasTool {
|
|
5
|
+
configureCanvas(props) {
|
|
6
|
+
const canvas = this._canvas;
|
|
7
|
+
|
|
8
|
+
// Enable drawing mode for the pencil tool
|
|
9
|
+
canvas.isDrawingMode = true;
|
|
10
|
+
|
|
11
|
+
// Initialize the freeDrawingBrush if not already set
|
|
12
|
+
if (!canvas.freeDrawingBrush) {
|
|
13
|
+
canvas.freeDrawingBrush = new fabric.PencilBrush(canvas);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Set brush properties
|
|
17
|
+
canvas.freeDrawingBrush.width = props.lineWidth || 1;
|
|
18
|
+
canvas.freeDrawingBrush.color = props.lineColor || 'black';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
attachListeners() {
|
|
22
|
+
const canvas = this._canvas;
|
|
23
|
+
|
|
24
|
+
// Set the canvas to drawing mode whenever Pencil is active
|
|
25
|
+
canvas.isDrawingMode = true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
detachListeners() {
|
|
29
|
+
const canvas = this._canvas;
|
|
30
|
+
|
|
31
|
+
// Disable drawing mode when switching away from the Pencil tool
|
|
32
|
+
canvas.isDrawingMode = false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default Pencil;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Rect, Textbox } from 'fabric';
|
|
2
|
+
|
|
3
|
+
class RectangleLabelObject {
|
|
4
|
+
constructor(canvas, text = 'Label', rectProps = {}, textProps = {}) {
|
|
5
|
+
this._canvas = canvas;
|
|
6
|
+
this._text = text;
|
|
7
|
+
|
|
8
|
+
// Ensure all essential properties are set for Rect and Textbox objects
|
|
9
|
+
const defaultRectProps = {
|
|
10
|
+
left: 10,
|
|
11
|
+
top: 10,
|
|
12
|
+
fill: 'transparent',
|
|
13
|
+
strokeWidth: 1,
|
|
14
|
+
width: 100,
|
|
15
|
+
height: 50,
|
|
16
|
+
selectable: false,
|
|
17
|
+
evented: false,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const defaultTextProps = {
|
|
21
|
+
left: 10,
|
|
22
|
+
top: 0,
|
|
23
|
+
fontSize: 16,
|
|
24
|
+
fill: 'black',
|
|
25
|
+
width: 100,
|
|
26
|
+
height: 30,
|
|
27
|
+
selectable: false,
|
|
28
|
+
evented: false,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Merge default properties with passed properties
|
|
32
|
+
this._rectObj = new Rect({ ...defaultRectProps, ...rectProps });
|
|
33
|
+
this._textObj = new Textbox(text, {
|
|
34
|
+
...defaultTextProps,
|
|
35
|
+
...textProps,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Trigger dimension calculations for the Textbox object
|
|
39
|
+
this._textObj.initDimensions();
|
|
40
|
+
|
|
41
|
+
// Attach event listeners for updating the label position
|
|
42
|
+
canvas.on('object:scaling', this.update);
|
|
43
|
+
canvas.on('object:moving', this.update);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
update = (e) => {
|
|
47
|
+
if (!this._textObj || !this._rectObj) return;
|
|
48
|
+
|
|
49
|
+
// Ensure text stays positioned above or inside the rectangle during scaling/moving
|
|
50
|
+
if (e.target === this._rectObj) {
|
|
51
|
+
this._textObj.set({
|
|
52
|
+
left: this._rectObj.left,
|
|
53
|
+
top: this._rectObj.top - this._textObj.getScaledHeight(),
|
|
54
|
+
width: this._rectObj.getScaledWidth(),
|
|
55
|
+
scaleX: 1,
|
|
56
|
+
scaleY: 1,
|
|
57
|
+
});
|
|
58
|
+
this._textObj.initDimensions(); // Force re-calculation if needed
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
setText(text) {
|
|
63
|
+
this._text = text;
|
|
64
|
+
this._textObj.set({ text });
|
|
65
|
+
this._textObj.initDimensions(); // Recalculate dimensions for new text
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default RectangleLabelObject;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import FabricCanvasTool from './fabrictool';
|
|
2
|
+
import RectangleLabelObject from './rectangle-label-object';
|
|
3
|
+
|
|
4
|
+
class RectangleLabel extends FabricCanvasTool {
|
|
5
|
+
configureCanvas(props) {
|
|
6
|
+
const canvas = this._canvas;
|
|
7
|
+
canvas.isDrawingMode = false;
|
|
8
|
+
canvas.selection = false;
|
|
9
|
+
canvas.forEachObject((o) => {
|
|
10
|
+
o.selectable = false;
|
|
11
|
+
o.evented = false;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Tool properties
|
|
15
|
+
this._width = props.lineWidth || 1;
|
|
16
|
+
this._color = props.lineColor || 'black';
|
|
17
|
+
this._fill = props.fillColor || 'transparent';
|
|
18
|
+
this._textString = props.text || '';
|
|
19
|
+
this._maxFontSize = 12;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
doMouseDown(o) {
|
|
23
|
+
const canvas = this._canvas;
|
|
24
|
+
this.isDown = true;
|
|
25
|
+
const pointer = canvas.getPointer(o.e);
|
|
26
|
+
this.startX = pointer.x;
|
|
27
|
+
this.startY = pointer.y;
|
|
28
|
+
|
|
29
|
+
// Create a labeled rectangle
|
|
30
|
+
this.rectangleLabel = new RectangleLabelObject(
|
|
31
|
+
canvas,
|
|
32
|
+
'New drawing',
|
|
33
|
+
{
|
|
34
|
+
left: this.startX,
|
|
35
|
+
top: this.startY,
|
|
36
|
+
originX: 'left',
|
|
37
|
+
originY: 'top',
|
|
38
|
+
stroke: this._color,
|
|
39
|
+
strokeWidth: this._width,
|
|
40
|
+
fill: this._fill,
|
|
41
|
+
selectable: false,
|
|
42
|
+
evented: false,
|
|
43
|
+
strokeUniform: true,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
left: this.startX,
|
|
47
|
+
top: this.startY - 12,
|
|
48
|
+
fontSize: this._maxFontSize,
|
|
49
|
+
backgroundColor: this._color,
|
|
50
|
+
selectable: false,
|
|
51
|
+
evented: false,
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
this._objects = this._objects
|
|
56
|
+
? [...this._objects, this.rectangleLabel]
|
|
57
|
+
: [this.rectangleLabel];
|
|
58
|
+
|
|
59
|
+
canvas.add(this.rectangleLabel._rectObj);
|
|
60
|
+
canvas.add(this.rectangleLabel._textObj);
|
|
61
|
+
canvas.renderAll();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
doMouseMove(o) {
|
|
65
|
+
if (!this.isDown) return;
|
|
66
|
+
const canvas = this._canvas;
|
|
67
|
+
const pointer = canvas.getPointer(o.e);
|
|
68
|
+
|
|
69
|
+
// Update rectangle and text positions
|
|
70
|
+
this.rectangleLabel._rectObj.set({
|
|
71
|
+
left: Math.min(this.startX, pointer.x),
|
|
72
|
+
top: Math.min(this.startY, pointer.y),
|
|
73
|
+
width: Math.abs(this.startX - pointer.x),
|
|
74
|
+
height: Math.abs(this.startY - pointer.y),
|
|
75
|
+
});
|
|
76
|
+
this.rectangleLabel._textObj.set({
|
|
77
|
+
left: this.rectangleLabel._rectObj.left,
|
|
78
|
+
top: this.rectangleLabel._rectObj.top - this._maxFontSize,
|
|
79
|
+
width: this.rectangleLabel._rectObj.getScaledWidth(),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
this.rectangleLabel._rectObj.setCoords();
|
|
83
|
+
this.rectangleLabel._textObj.setCoords();
|
|
84
|
+
canvas.renderAll();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
doMouseUp() {
|
|
88
|
+
this.isDown = false;
|
|
89
|
+
this._canvas.renderAll();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default RectangleLabel;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import FabricCanvasTool from './fabrictool';
|
|
2
|
+
import { Rect as FabricRect } from 'fabric'; // Import Rect specifically for Fabric v6
|
|
3
|
+
|
|
4
|
+
class Rectangle extends FabricCanvasTool {
|
|
5
|
+
configureCanvas(props) {
|
|
6
|
+
const canvas = this._canvas;
|
|
7
|
+
|
|
8
|
+
// Disable drawing mode and selection for other objects
|
|
9
|
+
canvas.isDrawingMode = false;
|
|
10
|
+
canvas.selection = false;
|
|
11
|
+
canvas.forEachObject((o) => {
|
|
12
|
+
o.selectable = false;
|
|
13
|
+
o.evented = false;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Set rectangle drawing properties
|
|
17
|
+
this._width = props.lineWidth || 1;
|
|
18
|
+
this._color = props.lineColor || 'black';
|
|
19
|
+
this._fill = props.fillColor || 'transparent';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
doMouseDown(o) {
|
|
23
|
+
const canvas = this._canvas;
|
|
24
|
+
this.isDown = true;
|
|
25
|
+
|
|
26
|
+
// Get initial pointer position for rectangle start
|
|
27
|
+
const pointer = canvas.getPointer(o.e);
|
|
28
|
+
this.startX = pointer.x;
|
|
29
|
+
this.startY = pointer.y;
|
|
30
|
+
|
|
31
|
+
// Create a new rectangle at the start position
|
|
32
|
+
this.rect = new FabricRect({
|
|
33
|
+
left: this.startX,
|
|
34
|
+
top: this.startY,
|
|
35
|
+
originX: 'left',
|
|
36
|
+
originY: 'top',
|
|
37
|
+
width: 0, // Initial width, will expand in doMouseMove
|
|
38
|
+
height: 0, // Initial height, will expand in doMouseMove
|
|
39
|
+
stroke: this._color,
|
|
40
|
+
strokeWidth: this._width,
|
|
41
|
+
fill: this._fill,
|
|
42
|
+
transparentCorners: false,
|
|
43
|
+
selectable: false,
|
|
44
|
+
evented: false,
|
|
45
|
+
strokeUniform: true,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Add rectangle to the canvas
|
|
49
|
+
canvas.add(this.rect);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
doMouseMove(o) {
|
|
53
|
+
if (!this.isDown) return;
|
|
54
|
+
const canvas = this._canvas;
|
|
55
|
+
const pointer = canvas.getPointer(o.e);
|
|
56
|
+
|
|
57
|
+
// Set rectangle dimensions based on pointer movement
|
|
58
|
+
this.rect.set({
|
|
59
|
+
left: Math.min(this.startX, pointer.x),
|
|
60
|
+
top: Math.min(this.startY, pointer.y),
|
|
61
|
+
width: Math.abs(this.startX - pointer.x),
|
|
62
|
+
height: Math.abs(this.startY - pointer.y),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
this.rect.setCoords();
|
|
66
|
+
|
|
67
|
+
// Render the canvas to show the updated rectangle
|
|
68
|
+
canvas.requestRenderAll();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
doMouseUp() {
|
|
72
|
+
this.isDown = false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default Rectangle;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*eslint no-unused-vars: 0*/
|
|
2
|
+
|
|
3
|
+
import FabricCanvasTool from './fabrictool';
|
|
4
|
+
|
|
5
|
+
class Select extends FabricCanvasTool {
|
|
6
|
+
configureCanvas(props) {
|
|
7
|
+
let canvas = this._canvas;
|
|
8
|
+
canvas.isDrawingMode = false;
|
|
9
|
+
canvas.selection = true;
|
|
10
|
+
canvas.forEachObject((o) => {
|
|
11
|
+
o.selectable = o.evented = true;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default Select;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determine the mouse position
|
|
3
|
+
*
|
|
4
|
+
* @param event the canvas event
|
|
5
|
+
* @returns *[] tuple of position x,y
|
|
6
|
+
* @private
|
|
7
|
+
*/
|
|
8
|
+
export const pointerPosition = (event) => {
|
|
9
|
+
event = event || window.event;
|
|
10
|
+
var target = event.target || event.srcElement,
|
|
11
|
+
style = target.currentStyle || window.getComputedStyle(target, null),
|
|
12
|
+
borderLeftWidth = parseInt(style['borderLeftWidth'], 10),
|
|
13
|
+
borderTopWidth = parseInt(style['borderTopWidth'], 10),
|
|
14
|
+
rect = target.getBoundingClientRect(),
|
|
15
|
+
_x = event.clientX - borderLeftWidth - rect.left,
|
|
16
|
+
_y = event.clientY - borderTopWidth - rect.top,
|
|
17
|
+
_touchX = event.changedTouches
|
|
18
|
+
? event.changedTouches[0].clientX - borderLeftWidth - rect.left
|
|
19
|
+
: null,
|
|
20
|
+
_touchY = event.changedTouches
|
|
21
|
+
? event.changedTouches[0].clientY - borderTopWidth - rect.top
|
|
22
|
+
: null;
|
|
23
|
+
return [_x || _touchX, _y || _touchY];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Calculate the distance of two x,y points
|
|
28
|
+
*
|
|
29
|
+
* @param point1 an object with x,y attributes representing the start point
|
|
30
|
+
* @param point2 an object with x,y attributes representing the end point
|
|
31
|
+
*
|
|
32
|
+
* @returns {number}
|
|
33
|
+
*/
|
|
34
|
+
export const linearDistance = (point1, point2) => {
|
|
35
|
+
let xs = point2.x - point1.x;
|
|
36
|
+
let ys = point2.y - point1.y;
|
|
37
|
+
return Math.sqrt(xs * xs + ys * ys);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Return a random uuid of the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
42
|
+
* @returns {string}
|
|
43
|
+
*/
|
|
44
|
+
export const uuid4 = () => {
|
|
45
|
+
let uuid = '',
|
|
46
|
+
ii;
|
|
47
|
+
for (ii = 0; ii < 32; ii += 1) {
|
|
48
|
+
switch (ii) {
|
|
49
|
+
case 8:
|
|
50
|
+
case 20:
|
|
51
|
+
uuid += '-';
|
|
52
|
+
uuid += ((Math.random() * 16) | 0).toString(16);
|
|
53
|
+
break;
|
|
54
|
+
case 12:
|
|
55
|
+
uuid += '-';
|
|
56
|
+
uuid += '4';
|
|
57
|
+
break;
|
|
58
|
+
case 16:
|
|
59
|
+
uuid += '-';
|
|
60
|
+
uuid += ((Math.random() * 4) | 8).toString(16);
|
|
61
|
+
break;
|
|
62
|
+
default:
|
|
63
|
+
uuid += ((Math.random() * 16) | 0).toString(16);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return uuid;
|
|
67
|
+
};
|
|
@@ -65,7 +65,7 @@ const SortableItem = ({
|
|
|
65
65
|
|
|
66
66
|
const EditButton = () => (
|
|
67
67
|
<Pencil
|
|
68
|
-
className={styles['
|
|
68
|
+
className={styles['edit']}
|
|
69
69
|
strokeWidth={1}
|
|
70
70
|
size={26}
|
|
71
71
|
onClick={(e) => {
|
|
@@ -97,7 +97,7 @@ const SortableItem = ({
|
|
|
97
97
|
|
|
98
98
|
{handleDelete && (
|
|
99
99
|
<TrashCan
|
|
100
|
-
className={styles
|
|
100
|
+
className={styles.delete}
|
|
101
101
|
strokeWidth={1}
|
|
102
102
|
size={26}
|
|
103
103
|
onClick={(e) => {
|