From f5dde41b0c9bfc895d4853a0c5ac0cbfda308782 Mon Sep 17 00:00:00 2001 From: Sam Watts Date: Thu, 18 Jul 2024 15:56:33 +0100 Subject: [PATCH 1/5] add zoom functionality --- .../frontend/src/DrawableCanvas.tsx | 58 +++++++++++++++++-- .../frontend/src/DrawableCanvasState.tsx | 25 +++++++- .../frontend/src/components/CanvasToolbar.tsx | 9 +++ 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx b/streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx index ad70899..3c4bb1b 100644 --- a/streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx +++ b/streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx @@ -72,11 +72,11 @@ const DrawableCanvas = ({ args }: ComponentProps) => { canvas.fireRightClick = true const [backgroundCanvas, setBackgroundCanvas] = useState( - new fabric.StaticCanvas("") + new fabric.Canvas("") ) const { canvasState: { - action: { shouldReloadCanvas, forceSendToStreamlit }, + action: { shouldReloadCanvas, forceSendToStreamlit, resetView }, currentState, initialState, }, @@ -87,6 +87,7 @@ const DrawableCanvas = ({ args }: ComponentProps) => { canRedo, forceStreamlitUpdate, resetState, + initalView, } = useCanvasState() /** @@ -97,7 +98,7 @@ const DrawableCanvas = ({ args }: ComponentProps) => { const c = new fabric.Canvas("canvas", { enableRetinaScaling: false, }) - const imgC = new fabric.StaticCanvas("backgroundimage-canvas", { + const imgC = new fabric.Canvas("backgroundimage-canvas", { enableRetinaScaling: false, }) setCanvas(c) @@ -125,7 +126,7 @@ const DrawableCanvas = ({ args }: ComponentProps) => { if (backgroundImageURL) { var bgImage = new Image(); bgImage.onload = function() { - backgroundCanvas.getContext().drawImage(bgImage, 0, 0); + backgroundCanvas.add(new fabric.Image(bgImage)); }; const baseUrl = getStreamlitBaseUrl() ?? "" bgImage.src = baseUrl + backgroundImageURL @@ -149,6 +150,17 @@ const DrawableCanvas = ({ args }: ComponentProps) => { } }, [canvas, shouldReloadCanvas, currentState]) + /** + * Reset view on resetView state change + */ + useEffect(() => { + if (resetView) { + canvas.setZoom(1.0); + backgroundCanvas.setZoom(1.0); + canvas.setViewportTransform([1, 0, 0, 1, 0, 0]); + backgroundCanvas.setViewportTransform([1, 0, 0, 1, 0, 0]); + } + }, [canvas, backgroundCanvas, resetView]) /** * Update canvas with selected tool * PS: add initialDrawing in dependency so user drawing update reinits tool @@ -174,6 +186,41 @@ const DrawableCanvas = ({ args }: ComponentProps) => { saveState(canvas.toJSON()) }) + function setZoom(canvas: fabric.Canvas, e: WheelEvent) { + var delta = e.deltaY; + var offsetX = e.offsetX; + var offsetY = e.offsetY; + var zoom = canvas.getZoom(); + + zoom *= 0.999 ** delta; + if (zoom > 20) zoom = 20; + if (zoom < 0.01) zoom = 0.01; + canvas.zoomToPoint(new fabric.Point(offsetX, offsetY), zoom); + + var vpt = canvas.viewportTransform? canvas.viewportTransform : [1, 0, 0, 1, 0, 0]; + if (zoom < 400 / 1000) { + vpt[4] = 200 - 1000 * zoom / 2; + vpt[5] = 200 - 1000 * zoom / 2; + } else { + if (vpt[4] >= 0) { + vpt[4] = 0; + } else if (vpt[4] < canvas.getWidth() - 1000 * zoom) { + vpt[4] = canvas.getWidth() - 1000 * zoom; + } + if (vpt[5] >= 0) { + vpt[5] = 0; + } else if (vpt[5] < canvas.getHeight() - 1000 * zoom) { + vpt[5] = canvas.getHeight() - 1000 * zoom; + } + } + } + + canvas.on('mouse:wheel', function(opt: any) { + setZoom(canvas, opt.e); + setZoom(backgroundCanvas, opt.e); + }); + + // Cleanup tool + send data to Streamlit events return () => { cleanupToolEvents() @@ -182,6 +229,7 @@ const DrawableCanvas = ({ args }: ComponentProps) => { } }, [ canvas, + backgroundCanvas, strokeWidth, strokeColor, displayRadius, @@ -190,6 +238,7 @@ const DrawableCanvas = ({ args }: ComponentProps) => { initialDrawing, saveState, forceStreamlitUpdate, + initalView, ]) /** @@ -256,6 +305,7 @@ const DrawableCanvas = ({ args }: ComponentProps) => { resetCallback={() => { resetState(initialState) }} + resetZoomCallback={initalView} /> )} diff --git a/streamlit_drawable_canvas/frontend/src/DrawableCanvasState.tsx b/streamlit_drawable_canvas/frontend/src/DrawableCanvasState.tsx index d3fdee2..91c638f 100644 --- a/streamlit_drawable_canvas/frontend/src/DrawableCanvasState.tsx +++ b/streamlit_drawable_canvas/frontend/src/DrawableCanvasState.tsx @@ -16,26 +16,37 @@ interface CanvasHistory { interface CanvasAction { shouldReloadCanvas: boolean // reload currentState into app canvas, on undo/redo forceSendToStreamlit: boolean // send currentState back to Streamlit + resetView: boolean // reset view to initial state } const NO_ACTION: CanvasAction = { shouldReloadCanvas: false, forceSendToStreamlit: false, + resetView: false, } const RELOAD_CANVAS: CanvasAction = { shouldReloadCanvas: true, forceSendToStreamlit: false, + resetView: false, } const SEND_TO_STREAMLIT: CanvasAction = { shouldReloadCanvas: false, forceSendToStreamlit: true, + resetView: false, } const RELOAD_AND_SEND_TO_STREAMLIT: CanvasAction = { shouldReloadCanvas: true, forceSendToStreamlit: true, + resetView: false, +} + +const RESET_VIEW: CanvasAction = { + shouldReloadCanvas: false, + forceSendToStreamlit: false, + resetView: true, } interface CanvasState { @@ -46,7 +57,7 @@ interface CanvasState { } interface Action { - type: "save" | "undo" | "redo" | "reset" | "forceSendToStreamlit" + type: "save" | "undo" | "redo" | "reset" | "forceSendToStreamlit" | "resetView" state?: Object } @@ -181,6 +192,14 @@ const canvasStateReducer = ( initialState: state.initialState, currentState: state.currentState, } + + case "resetView": + return { + history: { ...state.history }, + action: { ...RESET_VIEW }, + initialState: state.initialState, + currentState: state.currentState, + } default: throw new Error("TS should protect from this") } @@ -194,6 +213,7 @@ const initialState: CanvasState = { action: { forceSendToStreamlit: false, shouldReloadCanvas: false, + resetView: false, }, initialState: {}, currentState: {}, @@ -208,6 +228,7 @@ interface CanvasStateContextProps { canUndo: boolean canRedo: boolean resetState: (state: Object) => void + initalView: () => void } const CanvasStateContext = createContext( @@ -235,6 +256,7 @@ export const CanvasStateProvider = ({ (state) => dispatch({ type: "reset", state: state }), [dispatch] ) + const initalView = useCallback(() => dispatch({ type: "resetView" }), [dispatch]) const canUndo = canvasState.history.undoStack.length !== 0 const canRedo = canvasState.history.redoStack.length !== 0 @@ -250,6 +272,7 @@ export const CanvasStateProvider = ({ canRedo, forceStreamlitUpdate, resetState, + initalView, }} > {children} diff --git a/streamlit_drawable_canvas/frontend/src/components/CanvasToolbar.tsx b/streamlit_drawable_canvas/frontend/src/components/CanvasToolbar.tsx index 9b23c99..4fd3f72 100644 --- a/streamlit_drawable_canvas/frontend/src/components/CanvasToolbar.tsx +++ b/streamlit_drawable_canvas/frontend/src/components/CanvasToolbar.tsx @@ -50,6 +50,7 @@ interface CanvasToolbarProps { undoCallback: () => void redoCallback: () => void resetCallback: () => void + resetZoomCallback: () => void } const CanvasToolbar = ({ @@ -61,6 +62,7 @@ const CanvasToolbar = ({ undoCallback, redoCallback, resetCallback, + resetZoomCallback, }: CanvasToolbarProps) => { const GAP_BETWEEN_ICONS = 4 const ICON_SIZE = 24 @@ -94,6 +96,13 @@ const CanvasToolbar = ({ enabled: true, clickCallback: resetCallback, }, + { + imgUrl: bin, + altText: "Reset zoom", + invertX: false, + enabled: true, + clickCallback: resetZoomCallback, + }, ] return ( From 66ac4b555d11a631e8fdde1fe06a7f4b12ddb46a Mon Sep 17 00:00:00 2001 From: Sam Watts Date: Thu, 18 Jul 2024 15:57:34 +0100 Subject: [PATCH 2/5] add zoom functionality --- app.py | 44 +++++++++++++++ package-lock.json | 6 ++ streamlit_drawable_canvas/__init__.py | 2 +- .../frontend/package-lock.json | 55 ++++++++++++++++++- .../frontend/package.json | 3 +- 5 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 app.py create mode 100644 package-lock.json diff --git a/app.py b/app.py new file mode 100644 index 0000000..b62593c --- /dev/null +++ b/app.py @@ -0,0 +1,44 @@ +import pandas as pd +from PIL import Image +import streamlit as st +from streamlit_drawable_canvas import st_canvas +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler + +# Specify canvas parameters in application +drawing_mode = st.sidebar.selectbox( + "Drawing tool:", ("point", "freedraw", "line", "rect", "circle", "transform") +) + +stroke_width = st.sidebar.slider("Stroke width: ", 1, 25, 3) +if drawing_mode == 'point': + point_display_radius = st.sidebar.slider("Point display radius: ", 1, 25, 3) +stroke_color = st.sidebar.color_picker("Stroke color hex: ") +bg_color = st.sidebar.color_picker("Background color hex: ", "#eee") +bg_image = st.sidebar.file_uploader("Background image:", type=["png", "jpg"]) + +realtime_update = st.sidebar.checkbox("Update in realtime", True) + + +# Create a canvas component +canvas_result = st_canvas( + fill_color="rgba(255, 165, 0, 0.3)", # Fixed fill color with some opacity + stroke_width=stroke_width, + stroke_color=stroke_color, + background_color=bg_color, + background_image=Image.open(bg_image) if bg_image else None, + update_streamlit=realtime_update, + height=150, + drawing_mode=drawing_mode, + point_display_radius=point_display_radius if drawing_mode == 'point' else 0, + key="canvas", +) + +# Do something interesting with the image data and paths +if canvas_result.image_data is not None: + st.image(canvas_result.image_data) +if canvas_result.json_data is not None: + objects = pd.json_normalize(canvas_result.json_data["objects"]) # need to convert obj to str because PyArrow + for col in objects.select_dtypes(include=['object']).columns: + objects[col] = objects[col].astype("str") + st.dataframe(objects) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..01c11e5 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "streamlit-drawable-canvas", + "lockfileVersion": 2, + "requires": true, + "packages": {} +} diff --git a/streamlit_drawable_canvas/__init__.py b/streamlit_drawable_canvas/__init__.py index aa4445b..f7f0554 100644 --- a/streamlit_drawable_canvas/__init__.py +++ b/streamlit_drawable_canvas/__init__.py @@ -10,7 +10,7 @@ import streamlit.elements.image as st_image from PIL import Image -_RELEASE = True # on packaging, pass this to True +_RELEASE = False # on packaging, pass this to True if not _RELEASE: _component_func = components.declare_component( diff --git a/streamlit_drawable_canvas/frontend/package-lock.json b/streamlit_drawable_canvas/frontend/package-lock.json index 038b48c..5dba35f 100644 --- a/streamlit_drawable_canvas/frontend/package-lock.json +++ b/streamlit_drawable_canvas/frontend/package-lock.json @@ -17,7 +17,8 @@ "react-dom": "^16.13.1", "react-scripts": "4.0.3", "streamlit-component-lib": "^1.3.0", - "typescript": "^4.6.3" + "typescript": "^4.6.3", + "watch": "^1.0.2" }, "devDependencies": { "@types/fabric": "^3.6.2", @@ -16169,6 +16170,11 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/merge": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", + "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -23198,6 +23204,29 @@ "makeerror": "1.0.12" } }, + "node_modules/watch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", + "integrity": "sha512-1u+Z5n9Jc1E2c7qDO8SinPoZuHj7FgbgU1olSFoyaklduDvvtX7GMMtlE6OC9FTXq4KvNAOfj6Zu4vI1e9bAKA==", + "dependencies": { + "exec-sh": "^0.2.0", + "minimist": "^1.2.0" + }, + "bin": { + "watch": "cli.js" + }, + "engines": { + "node": ">=0.1.95" + } + }, + "node_modules/watch/node_modules/exec-sh": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", + "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", + "dependencies": { + "merge": "^1.2.0" + } + }, "node_modules/watchpack": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", @@ -37248,6 +37277,11 @@ } } }, + "merge": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", + "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==" + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -42859,6 +42893,25 @@ "makeerror": "1.0.12" } }, + "watch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", + "integrity": "sha512-1u+Z5n9Jc1E2c7qDO8SinPoZuHj7FgbgU1olSFoyaklduDvvtX7GMMtlE6OC9FTXq4KvNAOfj6Zu4vI1e9bAKA==", + "requires": { + "exec-sh": "^0.2.0", + "minimist": "^1.2.0" + }, + "dependencies": { + "exec-sh": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", + "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", + "requires": { + "merge": "^1.2.0" + } + } + } + }, "watchpack": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", diff --git a/streamlit_drawable_canvas/frontend/package.json b/streamlit_drawable_canvas/frontend/package.json index c63c137..5ff0872 100644 --- a/streamlit_drawable_canvas/frontend/package.json +++ b/streamlit_drawable_canvas/frontend/package.json @@ -12,7 +12,8 @@ "react-dom": "^16.13.1", "react-scripts": "4.0.3", "streamlit-component-lib": "^1.3.0", - "typescript": "^4.6.3" + "typescript": "^4.6.3", + "watch": "^1.0.2" }, "devDependencies": { "@types/fabric": "^3.6.2", From 16fd684b3edda7b4cfe20438c09a0ff37bdfd9c0 Mon Sep 17 00:00:00 2001 From: Sam Watts Date: Thu, 18 Jul 2024 16:01:20 +0100 Subject: [PATCH 3/5] Revert "add zoom functionality" This reverts commit 66ac4b555d11a631e8fdde1fe06a7f4b12ddb46a. --- app.py | 44 --------------- package-lock.json | 6 -- streamlit_drawable_canvas/__init__.py | 2 +- .../frontend/package-lock.json | 55 +------------------ .../frontend/package.json | 3 +- 5 files changed, 3 insertions(+), 107 deletions(-) delete mode 100644 app.py delete mode 100644 package-lock.json diff --git a/app.py b/app.py deleted file mode 100644 index b62593c..0000000 --- a/app.py +++ /dev/null @@ -1,44 +0,0 @@ -import pandas as pd -from PIL import Image -import streamlit as st -from streamlit_drawable_canvas import st_canvas -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler - -# Specify canvas parameters in application -drawing_mode = st.sidebar.selectbox( - "Drawing tool:", ("point", "freedraw", "line", "rect", "circle", "transform") -) - -stroke_width = st.sidebar.slider("Stroke width: ", 1, 25, 3) -if drawing_mode == 'point': - point_display_radius = st.sidebar.slider("Point display radius: ", 1, 25, 3) -stroke_color = st.sidebar.color_picker("Stroke color hex: ") -bg_color = st.sidebar.color_picker("Background color hex: ", "#eee") -bg_image = st.sidebar.file_uploader("Background image:", type=["png", "jpg"]) - -realtime_update = st.sidebar.checkbox("Update in realtime", True) - - -# Create a canvas component -canvas_result = st_canvas( - fill_color="rgba(255, 165, 0, 0.3)", # Fixed fill color with some opacity - stroke_width=stroke_width, - stroke_color=stroke_color, - background_color=bg_color, - background_image=Image.open(bg_image) if bg_image else None, - update_streamlit=realtime_update, - height=150, - drawing_mode=drawing_mode, - point_display_radius=point_display_radius if drawing_mode == 'point' else 0, - key="canvas", -) - -# Do something interesting with the image data and paths -if canvas_result.image_data is not None: - st.image(canvas_result.image_data) -if canvas_result.json_data is not None: - objects = pd.json_normalize(canvas_result.json_data["objects"]) # need to convert obj to str because PyArrow - for col in objects.select_dtypes(include=['object']).columns: - objects[col] = objects[col].astype("str") - st.dataframe(objects) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 01c11e5..0000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "streamlit-drawable-canvas", - "lockfileVersion": 2, - "requires": true, - "packages": {} -} diff --git a/streamlit_drawable_canvas/__init__.py b/streamlit_drawable_canvas/__init__.py index f7f0554..aa4445b 100644 --- a/streamlit_drawable_canvas/__init__.py +++ b/streamlit_drawable_canvas/__init__.py @@ -10,7 +10,7 @@ import streamlit.elements.image as st_image from PIL import Image -_RELEASE = False # on packaging, pass this to True +_RELEASE = True # on packaging, pass this to True if not _RELEASE: _component_func = components.declare_component( diff --git a/streamlit_drawable_canvas/frontend/package-lock.json b/streamlit_drawable_canvas/frontend/package-lock.json index 5dba35f..038b48c 100644 --- a/streamlit_drawable_canvas/frontend/package-lock.json +++ b/streamlit_drawable_canvas/frontend/package-lock.json @@ -17,8 +17,7 @@ "react-dom": "^16.13.1", "react-scripts": "4.0.3", "streamlit-component-lib": "^1.3.0", - "typescript": "^4.6.3", - "watch": "^1.0.2" + "typescript": "^4.6.3" }, "devDependencies": { "@types/fabric": "^3.6.2", @@ -16170,11 +16169,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==" - }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -23204,29 +23198,6 @@ "makeerror": "1.0.12" } }, - "node_modules/watch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", - "integrity": "sha512-1u+Z5n9Jc1E2c7qDO8SinPoZuHj7FgbgU1olSFoyaklduDvvtX7GMMtlE6OC9FTXq4KvNAOfj6Zu4vI1e9bAKA==", - "dependencies": { - "exec-sh": "^0.2.0", - "minimist": "^1.2.0" - }, - "bin": { - "watch": "cli.js" - }, - "engines": { - "node": ">=0.1.95" - } - }, - "node_modules/watch/node_modules/exec-sh": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", - "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", - "dependencies": { - "merge": "^1.2.0" - } - }, "node_modules/watchpack": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", @@ -37277,11 +37248,6 @@ } } }, - "merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==" - }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -42893,25 +42859,6 @@ "makeerror": "1.0.12" } }, - "watch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", - "integrity": "sha512-1u+Z5n9Jc1E2c7qDO8SinPoZuHj7FgbgU1olSFoyaklduDvvtX7GMMtlE6OC9FTXq4KvNAOfj6Zu4vI1e9bAKA==", - "requires": { - "exec-sh": "^0.2.0", - "minimist": "^1.2.0" - }, - "dependencies": { - "exec-sh": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", - "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", - "requires": { - "merge": "^1.2.0" - } - } - } - }, "watchpack": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", diff --git a/streamlit_drawable_canvas/frontend/package.json b/streamlit_drawable_canvas/frontend/package.json index 5ff0872..c63c137 100644 --- a/streamlit_drawable_canvas/frontend/package.json +++ b/streamlit_drawable_canvas/frontend/package.json @@ -12,8 +12,7 @@ "react-dom": "^16.13.1", "react-scripts": "4.0.3", "streamlit-component-lib": "^1.3.0", - "typescript": "^4.6.3", - "watch": "^1.0.2" + "typescript": "^4.6.3" }, "devDependencies": { "@types/fabric": "^3.6.2", From 0d174e69435f445aa292cad0e36af15de515fee9 Mon Sep 17 00:00:00 2001 From: Sam Watts Date: Fri, 9 Aug 2024 17:31:01 +0100 Subject: [PATCH 4/5] prevent page from scrolling while zooming --- streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx b/streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx index 3c4bb1b..9cf4060 100644 --- a/streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx +++ b/streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx @@ -218,8 +218,13 @@ const DrawableCanvas = ({ args }: ComponentProps) => { canvas.on('mouse:wheel', function(opt: any) { setZoom(canvas, opt.e); setZoom(backgroundCanvas, opt.e); + + opt.e.preventDefault(); + opt.e.stopPropagation(); }); + + // Cleanup tool + send data to Streamlit events return () => { From 1ede0441d329d67d2721e8b93f945a62f8f8cebe Mon Sep 17 00:00:00 2001 From: Sam Watts Date: Fri, 9 Aug 2024 18:07:20 +0100 Subject: [PATCH 5/5] add icon from material design --- .../frontend/src/components/CanvasToolbar.tsx | 3 ++- .../frontend/src/img/reset_zoom.png | Bin 0 -> 1228 bytes 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 streamlit_drawable_canvas/frontend/src/img/reset_zoom.png diff --git a/streamlit_drawable_canvas/frontend/src/components/CanvasToolbar.tsx b/streamlit_drawable_canvas/frontend/src/components/CanvasToolbar.tsx index 4fd3f72..f544134 100644 --- a/streamlit_drawable_canvas/frontend/src/components/CanvasToolbar.tsx +++ b/streamlit_drawable_canvas/frontend/src/components/CanvasToolbar.tsx @@ -5,6 +5,7 @@ import styles from "./CanvasToolbar.module.css" import bin from "../img/bin.png" import undo from "../img/undo.png" import download from "../img/download.png" +import resetZoom from "../img/reset_zoom.png" interface SquareIconProps { imgUrl: string @@ -97,7 +98,7 @@ const CanvasToolbar = ({ clickCallback: resetCallback, }, { - imgUrl: bin, + imgUrl: resetZoom, altText: "Reset zoom", invertX: false, enabled: true, diff --git a/streamlit_drawable_canvas/frontend/src/img/reset_zoom.png b/streamlit_drawable_canvas/frontend/src/img/reset_zoom.png new file mode 100644 index 0000000000000000000000000000000000000000..9322e5d87d567140e7e3e1e9fa383ed46e6eb184 GIT binary patch literal 1228 zcmV;-1T*`IP)Px(hDk(0RCr$PoqbZ^JTIA%vf&JL>Me_7!%`zja;zKK^L4-`!nbw?CiiYmyFV zL=W}1U!7=uk##cGb+v8poFI_N062-BF1UoL0dn`_>QTC`#QWv|N(w&|bP6EM09Xn? zB@o2{OiB1JAj1Bk^rBr9!1JH?#}KNI#kE9+jqjs$S}F$M<@N6qqoRqIRC7nz)#2Z^ zgd4I0;G~?eYwP>X{!>lg7wG(cA+4gS3#6p106OtEPnsBPHdc%%Y{Bd|_uAB#J0)cU zpw0I=qfR}hjQfTx05lWL9cg_RPHB8u0KB}u*J#=)Dg1Cuu^@7|lMW!J+OZV>0K*yr z6+p~nazqpAx-U+MDi*@-_U8M8wy)uRGyu5xoa%-pK))T-y-ep)0N~{&H+oDVkoE{1 z0N@eB?adXXzZ}AUb^=mFaDpjW5H$5nDd$T7QAac8lnemLo6MXkiN|^$3#@b(BmqDM zIY;pi5K9DC5&&ewHJ7}9&N*l*N|~b?z|x~XW}}v}7GwpG5*e&q&S*z=x_&KC1CRza z=iEPphO7nJU{e7=(vNmPjEH5ofvg4EG?WFvlA<54h;(U41z=6-=eQUH2X-3QM*~3Y zs2K=5ZOo;;cmU$LkIss75sW=fI)EkSf41oT_8dS?b%D0|07&QLz}OdYNi+ayQ=+Yh z7onzN5_AAw0mV^J02u#mkpoyU0L^o#Qou-?&d+jp&#=aP`bOb^@u!@v)&Oa3x)hgO z09`LJrT8KMAcun`0d##~8`9YWND;r0DTf0Nu#s#K4M3W3jQ!%4tMgZDQ_rEboB$9P z!~+md1u^R}#BbV&TO_~sniqiVu*Cw9gk=T5p`A;CAdMpf0GT>-^4f_r$1vtZIsnA> z$l}8iV5I=0Pdt`e2UZCH`K?$f7pxLMmxiX{0tYaX%%uegSx=-kRto@1L%_#7r8?dL zj6}GchN?TyQxRIRHWoAZx*; zROA2%0FZL>(iyn}AOS#AQPW+&GI9VU0O*2zbi&6T!2u8f#JHe!LS1d8FH({=V#MK_ zG?iQhX{#c1whjPQs&`$i6UMrb0Ic>bNaDhR-~c40N8V>ZZ~zGanp;yLH~;~FR7NK9 zQ$IK*flD3N@P6%Dlw1WlfDVNN7=)xdfaGyWNNwbihIed6I}T4lBoYq5QxGYXB85yX z0<pH8A9x@-~vl6oh(AD627vypPB7QUW zMF41zJj5>%IUlom0LZE5Fq*{xI6-Ls)FJ+-OSk~yzZZK^0Fb;qwQC%JF%bvg0E`td q?%o~X0E`td?%o~X0E`td?*2ccKdp{lFkklo0000