diff --git a/package-lock.json b/package-lock.json
index 23cafe6b..62728a18 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"daikon": "^1.2.42",
"jszip": "^3.10.1",
"react": "^17.0.2",
+ "react-color": "^2.19.3",
"react-dnd": "^14.0.2",
"react-dnd-html5-backend": "^14.0.0",
"react-dom": "^17.0.2",
@@ -2296,6 +2297,14 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
},
+ "node_modules/@icons/material": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
+ "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -17233,6 +17242,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "node_modules/lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+ },
"node_modules/lodash._reinterpolate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
@@ -17470,6 +17484,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/material-colors": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
+ "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
+ },
"node_modules/md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@@ -20518,6 +20537,23 @@
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
+ "node_modules/react-color": {
+ "version": "2.19.3",
+ "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz",
+ "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==",
+ "dependencies": {
+ "@icons/material": "^0.2.4",
+ "lodash": "^4.17.15",
+ "lodash-es": "^4.17.15",
+ "material-colors": "^1.2.1",
+ "prop-types": "^15.5.10",
+ "reactcss": "^1.2.0",
+ "tinycolor2": "^1.4.1"
+ },
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-dev-utils": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
@@ -21229,6 +21265,14 @@
"react-dom": ">=16.6.0"
}
},
+ "node_modules/reactcss": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
+ "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
+ "dependencies": {
+ "lodash": "^4.0.1"
+ }
+ },
"node_modules/read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@@ -24132,6 +24176,11 @@
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
"integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A=="
},
+ "node_modules/tinycolor2": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
+ "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
+ },
"node_modules/tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -28303,6 +28352,12 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
},
+ "@icons/material": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
+ "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
+ "requires": {}
+ },
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -39630,6 +39685,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+ },
"lodash._reinterpolate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
@@ -39822,6 +39882,11 @@
"object-visit": "^1.0.0"
}
},
+ "material-colors": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
+ "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
+ },
"md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@@ -42234,6 +42299,20 @@
}
}
},
+ "react-color": {
+ "version": "2.19.3",
+ "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz",
+ "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==",
+ "requires": {
+ "@icons/material": "^0.2.4",
+ "lodash": "^4.17.15",
+ "lodash-es": "^4.17.15",
+ "material-colors": "^1.2.1",
+ "prop-types": "^15.5.10",
+ "reactcss": "^1.2.0",
+ "tinycolor2": "^1.4.1"
+ }
+ },
"react-dev-utils": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
@@ -42690,6 +42769,14 @@
"prop-types": "^15.6.2"
}
},
+ "reactcss": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
+ "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
+ "requires": {
+ "lodash": "^4.0.1"
+ }
+ },
"read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@@ -44971,6 +45058,11 @@
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
"integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A=="
},
+ "tinycolor2": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
+ "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
+ },
"tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
diff --git a/package.json b/package.json
index 446e0330..8a186688 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
"daikon": "^1.2.42",
"jszip": "^3.10.1",
"react": "^17.0.2",
+ "react-color": "^2.19.3",
"react-dnd": "^14.0.2",
"react-dnd-html5-backend": "^14.0.0",
"react-dom": "^17.0.2",
diff --git a/public/sprite.svg b/public/sprite.svg
index 6e102f7c..693f7626 100644
--- a/public/sprite.svg
+++ b/public/sprite.svg
@@ -167,9 +167,17 @@
-
+
+
+
+
diff --git a/src/engine/Graphics2d.js b/src/engine/Graphics2d.js
index 1104c73a..8ced8c63 100644
--- a/src/engine/Graphics2d.js
+++ b/src/engine/Graphics2d.js
@@ -8,6 +8,7 @@ import { connect } from 'react-redux';
import Modes2d from '../store/Modes2d';
import StoreActionType from '../store/ActionTypes';
import ToolPick from './tools2d/ToolPick';
+import ToolPaint from './tools2d/ToolPaint';
import ToolDistance from './tools2d/ToolDistance';
import ToolAngle from './tools2d/ToolAngle';
import ToolArea from './tools2d/ToolArea';
@@ -71,6 +72,7 @@ class Graphics2d extends React.Component {
// tools2d
this.m_toolPick = new ToolPick(this);
+ this.m_toolPaint = new ToolPaint(this);
this.m_toolDistance = new ToolDistance(this);
this.m_toolAngle = new ToolAngle(this);
this.m_toolArea = new ToolArea(this);
@@ -205,6 +207,7 @@ class Graphics2d extends React.Component {
// console.log(`gra2d. render: wScreen*hScreen = ${wScreen} * ${hScreen}, but w*h=${w}*${h} `);
this.m_toolPick.setScreenDim(wScreen, hScreen);
+ this.m_toolPaint.setScreenDim(wScreen, hScreen);
this.m_toolDistance.setScreenDim(wScreen, hScreen);
this.m_toolAngle.setScreenDim(wScreen, hScreen);
this.m_toolArea.setScreenDim(wScreen, hScreen);
@@ -296,6 +299,7 @@ class Graphics2d extends React.Component {
// console.log(`gra2d. render: wScreen*hScreen = ${wScreen} * ${hScreen}, but w*h=${w}*${h} `);
this.m_toolPick.setScreenDim(wScreen, hScreen);
+ this.m_toolPaint.setScreenDim(wScreen, hScreen);
this.m_toolDistance.setScreenDim(wScreen, hScreen);
this.m_toolAngle.setScreenDim(wScreen, hScreen);
this.m_toolArea.setScreenDim(wScreen, hScreen);
@@ -390,6 +394,7 @@ class Graphics2d extends React.Component {
// console.log(`gra2d. render: wScreen*hScreen = ${wScreen} * ${hScreen}, but w*h=${w}*${h} `);
this.m_toolPick.setScreenDim(wScreen, hScreen);
+ this.m_toolPaint.setScreenDim(wScreen, hScreen);
this.m_toolDistance.setScreenDim(wScreen, hScreen);
this.m_toolAngle.setScreenDim(wScreen, hScreen);
this.m_toolArea.setScreenDim(wScreen, hScreen);
@@ -539,6 +544,7 @@ class Graphics2d extends React.Component {
})
.then(() => {
this.m_toolPick.render(ctx);
+ this.m_toolPaint.render(ctx, store);
this.m_toolDistance.render(ctx, store);
this.m_toolAngle.render(ctx, store);
this.m_toolArea.render(ctx, store);
@@ -566,10 +572,10 @@ class Graphics2d extends React.Component {
xPosNew = mouseX - (mouseX - store.render2dxPos) * (newZoom / zoom);
yPosNew = mouseY - (mouseY - store.render2dyPos) * (newZoom / zoom);
} else {
- const initialX = canvasRect.width * zoom + store.render2dxPos;
- const initialY = canvasRect.height * zoom + store.render2dyPos;
- xPosNew = initialX - (initialX - store.render2dxPos) * (newZoom / zoom);
- yPosNew = initialY - (initialY - store.render2dyPos) * (newZoom / zoom);
+ const centerX = (canvasRect.width * newZoom) / 2 + store.render2dxPos;
+ const centerY = (canvasRect.height * newZoom) / 2 + store.render2dyPos;
+ xPosNew = centerX - (centerX - store.render2dxPos) * (newZoom / zoom);
+ yPosNew = centerY - (centerY - store.render2dyPos) * (newZoom / zoom);
}
if (xPosNew < 0) {
@@ -600,6 +606,13 @@ class Graphics2d extends React.Component {
this.setState({ stateMouseDown: false });
+ if (indexTools2d === Tools2dType.PAINT) {
+ const store = this.props;
+ const box = this.m_mount.current.getBoundingClientRect();
+ const xScr = evt.clientX - box.left;
+ const yScr = evt.clientY - box.top;
+ this.m_toolPaint.onMouseUp(xScr, yScr, store);
+ }
if (indexTools2d === Tools2dType.DISTANCE) {
const store = this.props;
const box = this.m_mount.current.getBoundingClientRect();
@@ -660,6 +673,9 @@ class Graphics2d extends React.Component {
const xScr = xContainer;
const yScr = yContainer;
+ if (indexTools2d === Tools2dType.PAINT) {
+ this.m_toolPaint.onMouseMove(xScr, yScr, store);
+ }
if (indexTools2d === Tools2dType.DISTANCE) {
this.m_toolDistance.onMouseMove(xScr, yScr, store);
}
@@ -718,6 +734,9 @@ class Graphics2d extends React.Component {
case Tools2dType.INTENSITY:
this.m_toolPick.onMouseDown(xScr, yScr, store);
break;
+ case Tools2dType.PAINT:
+ this.m_toolPaint.onMouseDown(xScr, yScr, store);
+ break;
case Tools2dType.DISTANCE:
this.m_toolDistance.onMouseDown(xScr, yScr, store);
break;
@@ -754,6 +773,7 @@ class Graphics2d extends React.Component {
* Invoke clear all tools
*/
clear() {
+ this.m_toolPaint.clear();
this.m_toolDistance.clear();
this.m_toolAngle.clear();
this.m_toolArea.clear();
diff --git a/src/engine/tools2d/ToolDelete.js b/src/engine/tools2d/ToolDelete.js
index bf861718..fab4cea2 100644
--- a/src/engine/tools2d/ToolDelete.js
+++ b/src/engine/tools2d/ToolDelete.js
@@ -75,12 +75,13 @@ class ToolDelete {
y: yScr,
};
+ const toolPaint = this.m_objGraphics2d.m_toolPaint;
const toolDist = this.m_objGraphics2d.m_toolDistance;
const toolAngle = this.m_objGraphics2d.m_toolAngle;
const toolArea = this.m_objGraphics2d.m_toolArea;
const toolRect = this.m_objGraphics2d.m_toolRect;
const toolText = this.m_objGraphics2d.m_toolText;
- const tools = [toolDist, toolAngle, toolArea, toolRect, toolText];
+ const tools = [toolPaint, toolDist, toolAngle, toolArea, toolRect, toolText];
const trackedBefore = this.m_pointTracked !== null;
this.m_pointTracked = null;
const numTools = tools.length;
diff --git a/src/engine/tools2d/ToolPaint.js b/src/engine/tools2d/ToolPaint.js
new file mode 100644
index 00000000..d984e5c8
--- /dev/null
+++ b/src/engine/tools2d/ToolPaint.js
@@ -0,0 +1,112 @@
+import ToolDistance from './ToolDistance';
+import PointerChecker from '../utils/PointerChecker';
+
+class ToolPaint {
+ constructor(objGra) {
+ this.m_objGraphics2d = objGra;
+ this.m_wScreen = 0;
+ this.m_hScreen = 0;
+ this.m_lines = [];
+ this.m_mouseDown = false;
+ this.m_objEdit = null;
+ }
+
+ setScreenDim(wScr, hScr) {
+ this.m_wScreen = wScr;
+ this.m_hScreen = hScr;
+ }
+
+ getEditPoint(vScr, store) {
+ const numLines = this.m_lines.length;
+ for (let i = 0; i < numLines; i++) {
+ const objLine = this.m_lines[i];
+
+ if (objLine.points.length >= 2) {
+ for (let j = 1; j < objLine.points.length; j++) {
+ const vScrS = ToolDistance.textureToScreen(
+ objLine.points[j - 1].x,
+ objLine.points[j - 1].y,
+ this.m_wScreen,
+ this.m_hScreen,
+ store
+ );
+ const vScrE = ToolDistance.textureToScreen(objLine.points[j].x, objLine.points[j].y, this.m_wScreen, this.m_hScreen, store);
+
+ if (PointerChecker.isPointerOnLine(vScrS, vScrE, vScr)) {
+ this.m_objEdit = objLine;
+ return objLine.points[j - 1];
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ deleteObject() {
+ if (this.m_objEdit != null) {
+ const ind = this.m_lines.indexOf(this.m_objEdit);
+ if (ind >= 0) {
+ this.m_lines.splice(ind, 1);
+ }
+ }
+ }
+
+ onMouseDown(xScr, yScr, store) {
+ const vTex = ToolDistance.screenToTexture(xScr, yScr, this.m_wScreen, this.m_hScreen, store);
+ const newLine = {
+ points: [{ x: vTex.x, y: vTex.y }],
+ distMm: 0.0,
+ color: store.selectedColor,
+ };
+ this.m_lines.push(newLine);
+ this.m_mouseDown = true;
+ }
+
+ onMouseMove(xScr, yScr, store) {
+ if (!this.m_mouseDown) {
+ return;
+ }
+ const vTex = ToolDistance.screenToTexture(xScr, yScr, this.m_wScreen, this.m_hScreen, store);
+ const numLines = this.m_lines.length;
+ if (numLines > 0) {
+ const currentLine = this.m_lines[numLines - 1];
+ currentLine.points.push({ x: vTex.x, y: vTex.y });
+ this.m_objGraphics2d.forceUpdate();
+ }
+ }
+
+ onMouseUp() {
+ this.m_mouseDown = false;
+ }
+
+ clear() {
+ this.m_lines = [];
+ }
+
+ render(ctx, store) {
+ const numLines = this.m_lines.length;
+ ctx.lineWidth = 2;
+
+ for (let i = 0; i < numLines; i++) {
+ const objLine = this.m_lines[i];
+ const points = objLine.points;
+
+ if (points.length > 1) {
+ ctx.strokeStyle = objLine.color;
+ for (let j = 1; j < points.length; j++) {
+ const vsTex = points[j - 1];
+ const veTex = points[j];
+
+ const vs = ToolDistance.textureToScreen(vsTex.x, vsTex.y, this.m_wScreen, this.m_hScreen, store);
+ const ve = ToolDistance.textureToScreen(veTex.x, veTex.y, this.m_wScreen, this.m_hScreen, store);
+
+ ctx.beginPath();
+ ctx.moveTo(vs.x, vs.y);
+ ctx.lineTo(ve.x, ve.y);
+ ctx.stroke();
+ }
+ }
+ }
+ }
+}
+export default ToolPaint;
diff --git a/src/engine/tools2d/ToolTypes.js b/src/engine/tools2d/ToolTypes.js
index 4087ad85..406c8c99 100644
--- a/src/engine/tools2d/ToolTypes.js
+++ b/src/engine/tools2d/ToolTypes.js
@@ -24,5 +24,6 @@ const Tools2dType = {
ZOOM_100: 11,
FILTER: 12,
HAND: 13,
+ PAINT: 14,
};
export default Tools2dType;
diff --git a/src/store/ActionTypes.js b/src/store/ActionTypes.js
index 350ecd8a..712b791c 100644
--- a/src/store/ActionTypes.js
+++ b/src/store/ActionTypes.js
@@ -53,5 +53,6 @@ const StoreActionType = {
SET_SHOW_MODAL_CONFIRMATION: 41,
SET_SHOW_MODAL_WINDOW_WC: 42,
SET_SHOW_MODAL_SELECT_FILES: 43,
+ SET_SELECTED_COLOR: 44,
};
export default StoreActionType;
diff --git a/src/store/Store.js b/src/store/Store.js
index bdd5fcf0..dd2d8dbb 100644
--- a/src/store/Store.js
+++ b/src/store/Store.js
@@ -52,6 +52,7 @@ export const initialState = {
showModalConfirmation: false,
showModalWindowCW: false,
showModalSelectFiles: false,
+ selectedColor: '#ffff00',
};
//
// App reducer
@@ -144,6 +145,8 @@ const medReducer = (state = initialState, action) => {
return Object.assign({}, state, { spinnerTitle: action.spinnerTitle });
case StoreActionType.SET_SPINNER_PROGRESS:
return Object.assign({}, state, { spinnerProgress: action.spinnerProgress });
+ case StoreActionType.SET_SELECTED_COLOR:
+ return Object.assign({}, state, { selectedColor: action.selectedColor });
default:
return state;
}
diff --git a/src/ui/Header/Header.module.css b/src/ui/Header/Header.module.css
index 420d1b8a..df2c79c9 100644
--- a/src/ui/Header/Header.module.css
+++ b/src/ui/Header/Header.module.css
@@ -1,6 +1,7 @@
.header {
display: flex;
gap: 5px;
+ z-index: 12;
}
.header_button {
diff --git a/src/ui/Main.module.css b/src/ui/Main.module.css
index c34629c0..9a4c1194 100644
--- a/src/ui/Main.module.css
+++ b/src/ui/Main.module.css
@@ -198,7 +198,7 @@
cursor: all-scroll;
border-radius: 24px;
transition: opacity 300ms ease-in-out;
- z-index: 1100;
+ z-index: 11;
}
.left {
top: 8%;
diff --git a/src/ui/Panels/ColorPicker/ColorPicker.css b/src/ui/Panels/ColorPicker/ColorPicker.css
new file mode 100644
index 00000000..929ab9f6
--- /dev/null
+++ b/src/ui/Panels/ColorPicker/ColorPicker.css
@@ -0,0 +1,9 @@
+.colorPicker {
+ position: absolute;
+ top: 100%;
+ right: 0;
+ cursor: pointer;
+}
+.sketchPicker {
+ background-color: rgba(41, 43, 46, 0.95) !important;
+}
diff --git a/src/ui/Panels/ColorPicker/ColorPicker.jsx b/src/ui/Panels/ColorPicker/ColorPicker.jsx
new file mode 100644
index 00000000..f4c5c5a5
--- /dev/null
+++ b/src/ui/Panels/ColorPicker/ColorPicker.jsx
@@ -0,0 +1,18 @@
+import { SketchPicker } from 'react-color';
+
+const ColorPicker = ({ selectedColor, onChange, sketchPickerClass }) => {
+ return (
+
+
+
+ );
+};
+
+export default ColorPicker;
diff --git a/src/ui/Panels/Mode2dSettingsPanel.jsx b/src/ui/Panels/Mode2dSettingsPanel.jsx
index 492ba893..d1b08b6e 100644
--- a/src/ui/Panels/Mode2dSettingsPanel.jsx
+++ b/src/ui/Panels/Mode2dSettingsPanel.jsx
@@ -8,11 +8,22 @@ import { SegmentationProperty } from './Properties2d/SegmentationProperty';
import SelectVolumeProperty from './Properties2d/SelectVolumeProperty';
import { SliderCaption } from '../Form';
import { TransverseProperty } from './Properties2d/TransverseProperty';
-import { useSelector } from 'react-redux';
+import { useSelector, useDispatch } from 'react-redux';
+import ColorPicker from '../Panels/ColorPicker/ColorPicker';
+import './ColorPicker/ColorPicker.css';
+import StoreActionType from '../../store/ActionTypes';
+import Tools2dType from '../../engine/tools2d/ToolTypes';
export const Mode2dSettingsPanel = () => {
const { volumeSet } = useSelector((state) => state);
const { m_volumes } = volumeSet;
+ const { indexTools2d } = useSelector((state) => state);
+ const { selectedColor } = useSelector((state) => state);
+ const dispatch = useDispatch();
+
+ const handleColorChange = (newColor) => {
+ dispatch({ type: StoreActionType.SET_SELECTED_COLOR, selectedColor: newColor.hex });
+ };
return (
<>
@@ -20,6 +31,12 @@ export const Mode2dSettingsPanel = () => {
{m_volumes.length > 1 && }
+ {indexTools2d === Tools2dType.PAINT && (
+
+ )}
>
);
};
diff --git a/src/ui/TopToolbar/ExploreTools.jsx b/src/ui/TopToolbar/ExploreTools.jsx
index 48cca240..1ddf7110 100644
--- a/src/ui/TopToolbar/ExploreTools.jsx
+++ b/src/ui/TopToolbar/ExploreTools.jsx
@@ -47,6 +47,12 @@ const ExploreTools = (props) => {
handler: mediator.bind(null, Tools2dType.INTENSITY),
id: Tools2dType.INTENSITY,
},
+ {
+ icon: 'paint',
+ caption: 'Paint',
+ handler: mediator.bind(null, Tools2dType.PAINT),
+ id: Tools2dType.PAINT,
+ },
{
icon: 'line',
caption: 'Measure distance between voxels',
diff --git a/src/ui/UiZoomTools.jsx b/src/ui/UiZoomTools.jsx
index ca187212..e84c5863 100644
--- a/src/ui/UiZoomTools.jsx
+++ b/src/ui/UiZoomTools.jsx
@@ -27,10 +27,10 @@ const UiZoomTools = (props) => {
xPosNew = props.render2dxPos + (canvasRect.width / 2) * Math.abs(step);
yPosNew = props.render2dyPos + (canvasRect.height / 2) * Math.abs(step);
} else if (buttonId === Tools2dType.ZOOM_OUT && newZoom < 1) {
- const initialX = canvasRect.width * currentZoom + props.render2dxPos;
- const initialY = canvasRect.height * currentZoom + props.render2dyPos;
- xPosNew = initialX - (initialX - props.render2dxPos) * (newZoom / currentZoom);
- yPosNew = initialY - (initialY - props.render2dyPos) * (newZoom / currentZoom);
+ const centerX = (canvasRect.width * newZoom) / 2 + props.render2dxPos;
+ const centerY = (canvasRect.height * newZoom) / 2 + props.render2dyPos;
+ xPosNew = centerX - (centerX - props.render2dxPos) * (newZoom / currentZoom);
+ yPosNew = centerY - (centerY - props.render2dyPos) * (newZoom / currentZoom);
}
if (xPosNew < 0) {