pcm-shared-components 0.0.45 → 0.0.48
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/README.md +23 -0
- package/dist/components/Buttons/CanvasPaint/index.js +207 -0
- package/dist/components/Buttons/CustomFab/CustomFab.js +9 -5
- package/dist/components/Buttons/HelpButton/HelpButton.js +16 -5
- package/dist/components/Buttons/ImageCanvasDraw/components/Controls.js +191 -0
- package/dist/components/Buttons/ImageCanvasDraw/constants/index.js +1 -0
- package/dist/components/Buttons/ImageCanvasDraw/constants/types.js +4 -0
- package/dist/components/Buttons/ImageCanvasDraw/index.js +183 -0
- package/dist/components/Buttons/ImageCanvasDraw/service/image_tools.js +37 -0
- package/dist/components/Buttons/ImageCanvasDraw/service/local_storage.js +20 -0
- package/dist/components/Buttons/ImageCanvasDraw/testMap.test.js +1 -0
- package/dist/styles/tailwind.css +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { useState, useRef, useEffect } from 'react';
|
|
2
|
+
import CanvasDraw from "react-canvas-draw";
|
|
3
|
+
import Controls from './components/Controls';
|
|
4
|
+
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
|
|
5
|
+
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
|
6
|
+
import Button from '@mui/material/Button';
|
|
7
|
+
import { getStorage, setStorage } from './service/local_storage';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
/**
|
|
10
|
+
* Displays an image that can is used to draw on to generate maps with highlighted routes.
|
|
11
|
+
*
|
|
12
|
+
* - Requires the ```b64DataUrl``` props to contain a dataUrl string.
|
|
13
|
+
* - Returns the ```data``` inside the onSave(data) function passed to the component.
|
|
14
|
+
*
|
|
15
|
+
* ### Importing the component
|
|
16
|
+
|
|
17
|
+
```//PitchCamp shared component
|
|
18
|
+
import {ImageCanvasDraw} from 'pcm-shared-components';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const ImageCanvasDraw = props => {
|
|
25
|
+
const {
|
|
26
|
+
onSave,
|
|
27
|
+
outputFormat,
|
|
28
|
+
showDownloadButton,
|
|
29
|
+
b64DataUrl
|
|
30
|
+
} = props;
|
|
31
|
+
const [state, setState] = useState({
|
|
32
|
+
drawerOpen: true,
|
|
33
|
+
color: "darkorange",
|
|
34
|
+
width: 0,
|
|
35
|
+
height: 0,
|
|
36
|
+
brushRadius: 5,
|
|
37
|
+
lazyRadius: 2,
|
|
38
|
+
imageScale: 1.5,
|
|
39
|
+
imageQuality: 0.5,
|
|
40
|
+
b64DataUrl: b64DataUrl,
|
|
41
|
+
imageCompressionOptions: {
|
|
42
|
+
maxSizeMB: 0.4,
|
|
43
|
+
maxWidthOrHeight: 1920,
|
|
44
|
+
useWebWorker: true,
|
|
45
|
+
maxIteration: 10
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
const saveableCanvas = useRef();
|
|
49
|
+
|
|
50
|
+
const setImageSize = imageUrl => {
|
|
51
|
+
try {
|
|
52
|
+
const img = new Image();
|
|
53
|
+
|
|
54
|
+
img.onload = () => {
|
|
55
|
+
//Scale the image down
|
|
56
|
+
const new_width = Number(img.width) / Number(state.imageScale);
|
|
57
|
+
const new_height = Number(img.height) / Number(state.imageScale); // Create a temporary canvas to draw the downscaled image on.
|
|
58
|
+
|
|
59
|
+
let canvas = document.createElement("canvas");
|
|
60
|
+
canvas.width = new_width;
|
|
61
|
+
canvas.height = new_height; // Draw the downscaled image on the canvas and return the new data URL.
|
|
62
|
+
|
|
63
|
+
let ctx = canvas.getContext("2d");
|
|
64
|
+
ctx.drawImage(img, 0, 0, new_width, new_height);
|
|
65
|
+
const newDataUrl = canvas.toDataURL("image/jpeg", state.imageQuality);
|
|
66
|
+
setState(previousState => {
|
|
67
|
+
return { ...previousState,
|
|
68
|
+
...getStorage(),
|
|
69
|
+
height: new_height,
|
|
70
|
+
width: new_width,
|
|
71
|
+
b64DataUrl: newDataUrl
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
img.src = imageUrl;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('error in setImageSize', error);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
//Get the scaled down image and width, height
|
|
84
|
+
setImageSize(state.b64DataUrl);
|
|
85
|
+
}, []);
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (saveableCanvas && saveableCanvas.current) {
|
|
88
|
+
//Refresh the canvas each time a props changes
|
|
89
|
+
saveableCanvas.current.drawImage();
|
|
90
|
+
setStorage(state);
|
|
91
|
+
}
|
|
92
|
+
}, [state]);
|
|
93
|
+
|
|
94
|
+
const DrawerButtonOpenClose = ({
|
|
95
|
+
children
|
|
96
|
+
}) => /*#__PURE__*/React.createElement(Button, {
|
|
97
|
+
style: {
|
|
98
|
+
minWidth: 6,
|
|
99
|
+
padding: 0,
|
|
100
|
+
margin: 0
|
|
101
|
+
},
|
|
102
|
+
color: "secondary",
|
|
103
|
+
onClick: () => {
|
|
104
|
+
setState(previousState => {
|
|
105
|
+
return { ...previousState,
|
|
106
|
+
drawerOpen: !previousState.drawerOpen
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}, children);
|
|
111
|
+
|
|
112
|
+
if (state.width && state.width !== 0) {
|
|
113
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
114
|
+
className: "flex flex-row overflow-hidden"
|
|
115
|
+
}, state.drawerOpen ? /*#__PURE__*/React.createElement("div", {
|
|
116
|
+
className: "flex flex-row",
|
|
117
|
+
style: {
|
|
118
|
+
width: 'auto'
|
|
119
|
+
}
|
|
120
|
+
}, /*#__PURE__*/React.createElement(Controls, {
|
|
121
|
+
state: state,
|
|
122
|
+
setState: setState,
|
|
123
|
+
saveableCanvas: saveableCanvas,
|
|
124
|
+
onSave: onSave,
|
|
125
|
+
outputFormat: outputFormat,
|
|
126
|
+
showDownloadButton: showDownloadButton
|
|
127
|
+
}), /*#__PURE__*/React.createElement(DrawerButtonOpenClose, null, /*#__PURE__*/React.createElement(ChevronLeftIcon, null))) : /*#__PURE__*/React.createElement("div", {
|
|
128
|
+
className: "flex flex-row justify-end"
|
|
129
|
+
}, /*#__PURE__*/React.createElement(DrawerButtonOpenClose, null, /*#__PURE__*/React.createElement(ChevronRightIcon, null))), state.width !== 0 && /*#__PURE__*/React.createElement("div", {
|
|
130
|
+
className: "overflow-scroll"
|
|
131
|
+
}, /*#__PURE__*/React.createElement(CanvasDraw, {
|
|
132
|
+
className: "",
|
|
133
|
+
ref: saveableCanvas,
|
|
134
|
+
onChange: evt => console.log("onChange", evt) // enablePanAndZoom //Don't enable pan and zoom or else it gets too complicated when saving...
|
|
135
|
+
// zoomExtents={{ min: 0.33, max: 10 }}
|
|
136
|
+
,
|
|
137
|
+
clampLinesToDocument: true,
|
|
138
|
+
hideInterface: false,
|
|
139
|
+
hideGrid: false,
|
|
140
|
+
backgroundColor: 'rgba(34,34,34,0.2)',
|
|
141
|
+
brushColor: state.color,
|
|
142
|
+
brushRadius: state.brushRadius,
|
|
143
|
+
lazyRadius: state.lazyRadius,
|
|
144
|
+
canvasWidth: Number(state.width) / Number(state.imageScale),
|
|
145
|
+
canvasHeight: Number(state.height) / Number(state.imageScale),
|
|
146
|
+
catenaryColor: 'black',
|
|
147
|
+
gridColor: "#ccc",
|
|
148
|
+
imgSrc: state.b64DataUrl
|
|
149
|
+
})));
|
|
150
|
+
} else {
|
|
151
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, "loading...");
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export default ImageCanvasDraw;
|
|
156
|
+
ImageCanvasDraw.defaultProps = {
|
|
157
|
+
onSave: undefined,
|
|
158
|
+
outputFormat: 'blob',
|
|
159
|
+
showDownloadButton: undefined,
|
|
160
|
+
b64DataUrl: undefined
|
|
161
|
+
};
|
|
162
|
+
ImageCanvasDraw.propTypes = {
|
|
163
|
+
/** On save function to execute returns either base64 or blob format based on the output format specified
|
|
164
|
+
*
|
|
165
|
+
* - onSave(data) data is either a **``blob``** or a **``base64``**
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
onSave = (data) =>{
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
*/
|
|
173
|
+
onSave: PropTypes.func,
|
|
174
|
+
|
|
175
|
+
/** Specified the type of data the onSave function will return */
|
|
176
|
+
outputFormat: PropTypes.oneOf(['blob', 'base64']),
|
|
177
|
+
|
|
178
|
+
/** If specified then we show the download button which is mainly used for testing to display what the canvas is exporting */
|
|
179
|
+
showDownloadButton: PropTypes.bool,
|
|
180
|
+
|
|
181
|
+
/** This is the image in a base 64 url format to use as the base image to draw on */
|
|
182
|
+
b64DataUrl: PropTypes.string.isRequired
|
|
183
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const combineDrawing = canvasRef => {
|
|
2
|
+
try {
|
|
3
|
+
const width = canvasRef.current.props.canvasWidth;
|
|
4
|
+
const height = canvasRef.current.props.canvasHeight;
|
|
5
|
+
const background = canvasRef.current.canvasContainer.children[0]; // const test = canvasRef.current.canvasContainer.children[0];
|
|
6
|
+
|
|
7
|
+
const drawing = canvasRef.current.canvasContainer.children[1];
|
|
8
|
+
const canvas = document.createElement('canvas');
|
|
9
|
+
canvas.width = width;
|
|
10
|
+
canvas.height = height; // composite now
|
|
11
|
+
|
|
12
|
+
canvas.getContext('2d').drawImage(background, 0, 0);
|
|
13
|
+
canvas.getContext('2d').globalAlpha = 1.0;
|
|
14
|
+
canvas.getContext('2d').drawImage(drawing, 0, 0); // canvas.getContext('2d').drawImage(test, 0, 0);
|
|
15
|
+
|
|
16
|
+
const dataUri = canvas.toDataURL('image/jpeg', 1.0);
|
|
17
|
+
const data = dataUri.split(',')[1];
|
|
18
|
+
const mimeType = dataUri.split(';')[0].slice(5);
|
|
19
|
+
const bytes = window.atob(data);
|
|
20
|
+
const buf = new ArrayBuffer(bytes.length);
|
|
21
|
+
const arr = new Uint8Array(buf);
|
|
22
|
+
|
|
23
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
24
|
+
arr[i] = bytes.charCodeAt(i);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const blob = new Blob([arr], {
|
|
28
|
+
type: mimeType
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
blob: blob,
|
|
32
|
+
dataUri: dataUri
|
|
33
|
+
};
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error('Error in combineDrawing: ', error);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const STORAGE_NAME = 'PC_IMAGE_DRAW_STATES';
|
|
2
|
+
export const getStorage = () => {
|
|
3
|
+
try {
|
|
4
|
+
return JSON.parse(localStorage.getItem(STORAGE_NAME));
|
|
5
|
+
} catch (error) {
|
|
6
|
+
console.error('Error in getting storage for IMAGE Draw:', error);
|
|
7
|
+
setStorage('');
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
export const setStorage = value => {
|
|
11
|
+
try {
|
|
12
|
+
//Need to filter out the b64DataUrl object from the state or else it might slow down the browser...
|
|
13
|
+
let new_value = Object.fromEntries(Object.entries(value).filter(([key, value]) => key !== 'b64DataUrl'));
|
|
14
|
+
console.log('debug new_value', new_value);
|
|
15
|
+
localStorage.setItem(STORAGE_NAME, JSON.stringify(new_value));
|
|
16
|
+
} catch (error) {
|
|
17
|
+
console.error('Error in setting storage for IMAGE Draw:', error);
|
|
18
|
+
setStorage('');
|
|
19
|
+
}
|
|
20
|
+
};
|