Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Polypath #51

Merged
merged 6 commits into from
Jun 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions streamlit_drawable_canvas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ def st_canvas(
Height of canvas in pixels. Defaults to 400.
width: int
Width of canvas in pixels. Defaults to 600.
drawing_mode: {'freedraw', 'transform', 'line', 'rect', 'circle'}
Enable free drawing when "freedraw", object manipulation when "transform", "line", "rect", "circle".
drawing_mode: {'freedraw', 'transform', 'line', 'rect', 'circle', 'polypath'}
Enable free drawing when "freedraw", object manipulation when "transform", "line", "rect", "circle", "polypath".
Defaults to "freedraw".
initial_drawing: dict
Redraw canvas with given initial_drawing. If changed to None then empties canvas.
Expand Down Expand Up @@ -123,7 +123,7 @@ def st_canvas(
strokeColor=stroke_color,
backgroundColor=background_color,
backgroundImage=background_image,
realtimeUpdateStreamlit=update_streamlit,
realtimeUpdateStreamlit=update_streamlit and (drawing_mode != 'polypath'),
canvasHeight=height,
canvasWidth=width,
drawingMode=drawing_mode,
Expand Down
9 changes: 8 additions & 1 deletion streamlit_drawable_canvas/frontend/src/DrawableCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ const DrawableCanvas = ({ args }: ComponentProps) => {
* State initialization
*/
const [canvas, setCanvas] = useState(new fabric.Canvas(""))
canvas.stopContextMenu = true
canvas.fireRightClick = true

const [backgroundCanvas, setBackgroundCanvas] = useState(
new fabric.StaticCanvas("")
)
Expand Down Expand Up @@ -142,8 +145,11 @@ const DrawableCanvas = ({ args }: ComponentProps) => {
strokeColor: strokeColor,
})

canvas.on("mouse:up", () => {
canvas.on("mouse:up", (e: any) => {
saveState(canvas.toJSON())
if (e["button"] === 3) {
andfanilo marked this conversation as resolved.
Show resolved Hide resolved
forceStreamlitUpdate()
andfanilo marked this conversation as resolved.
Show resolved Hide resolved
}
})

canvas.on("mouse:dblclick", () => {
Expand All @@ -164,6 +170,7 @@ const DrawableCanvas = ({ args }: ComponentProps) => {
drawingMode,
initialDrawing,
saveState,
forceStreamlitUpdate,
])

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ const SEND_TO_STREAMLIT: CanvasAction = {
forceSendToStreamlit: true,
}

const RELOAD_AND_SEND_TO_STREAMLIT: CanvasAction = {
shouldReloadCanvas: true,
forceSendToStreamlit: true,
}

interface CanvasState {
history: CanvasHistory
action: CanvasAction
Expand Down Expand Up @@ -165,7 +170,7 @@ const canvasStateReducer = (
undoStack: [],
redoStack: [],
},
action: { ...RELOAD_CANVAS },
action: { ...RELOAD_AND_SEND_TO_STREAMLIT },
initialState: action.state,
currentState: action.state,
}
Expand Down
5 changes: 4 additions & 1 deletion streamlit_drawable_canvas/frontend/src/lib/circle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class CircleTool extends FabricTool {

onMouseDown(o: any) {
let canvas = this._canvas
let _clicked = o.e["button"]
this.isMouseDown = true
let pointer = canvas.getPointer(o.e)
this.currentStartX = pointer.x
Expand All @@ -55,7 +56,9 @@ class CircleTool extends FabricTool {
evented: false,
radius: this._minRadius,
})
canvas.add(this.currentCircle)
if (_clicked === 0) {
canvas.add(this.currentCircle)
}
andfanilo marked this conversation as resolved.
Show resolved Hide resolved
}

onMouseMove(o: any) {
Expand Down
2 changes: 2 additions & 0 deletions streamlit_drawable_canvas/frontend/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import PolypathTool from "./polypath"
import CircleTool from "./circle"
import FabricTool from "./fabrictool"
import FreedrawTool from "./freedraw"
Expand All @@ -7,6 +8,7 @@ import TransformTool from "./transform"

// TODO: Should make TS happy on the Map of selectedTool --> FabricTool
const tools: any = {
polypath: PolypathTool,
circle: CircleTool,
freedraw: FreedrawTool,
line: LineTool,
Expand Down
9 changes: 8 additions & 1 deletion streamlit_drawable_canvas/frontend/src/lib/line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class LineTool extends FabricTool {

onMouseDown(o: any) {
let canvas = this._canvas
let _clicked = o.e["button"]
this.isMouseDown = true
var pointer = canvas.getPointer(o.e)
var points = [pointer.x, pointer.y, pointer.x, pointer.y]
Expand All @@ -44,7 +45,9 @@ class LineTool extends FabricTool {
selectable: false,
evented: false,
})
canvas.add(this.currentLine)
if (_clicked === 0) {
canvas.add(this.currentLine)
}
}

onMouseMove(o: any) {
Expand All @@ -58,6 +61,10 @@ class LineTool extends FabricTool {

onMouseUp(o: any) {
this.isMouseDown = false
let canvas = this._canvas
if (this.currentLine.width === 0 && this.currentLine.height === 0) {
canvas.remove(this.currentLine)
}
andfanilo marked this conversation as resolved.
Show resolved Hide resolved
}

onMouseOut(o: any) {
Expand Down
159 changes: 159 additions & 0 deletions streamlit_drawable_canvas/frontend/src/lib/polypath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { fabric } from "fabric"
import FabricTool, { ConfigureCanvasProps } from "./fabrictool"

class PolypathTool extends FabricTool {
isMouseDown: boolean = false
fillColor: string = "#ffffff"
strokeWidth: number = 10
strokeColor: string = "#ffffff"
startCircle: fabric.Circle = new fabric.Circle()
currentLine: fabric.Line = new fabric.Line()
currentPath: fabric.Path = new fabric.Path()
_pathString: string = "M "

configureCanvas({
strokeWidth,
strokeColor,
fillColor,
}: ConfigureCanvasProps): () => void {
this._canvas.isDrawingMode = false
this._canvas.selection = false
this._canvas.forEachObject((o) => (o.selectable = o.evented = false))

this.strokeWidth = strokeWidth
this.strokeColor = strokeColor
this.fillColor = fillColor

this._canvas.on("mouse:down", (e: any) => this.onMouseDown(e))
this._canvas.on("mouse:move", (e: any) => this.onMouseMove(e))
this._canvas.on("mouse:up", (e: any) => this.onMouseUp(e))
this._canvas.on("mouse:out", (e: any) => this.onMouseOut(e))
this._canvas.on("mouse:dblclick", (e: any) => this.onMouseDoubleClick(e))
return () => {
this._canvas.off("mouse:down")
this._canvas.off("mouse:move")
this._canvas.off("mouse:up")
this._canvas.off("mouse:out")
this._canvas.off("mouse:dblclick")
}
}

onMouseDown(o: any) {
let canvas = this._canvas
let _clicked = o.e["button"]
let _start = false
if (this._pathString === "M ") {
_start = true
}

this.isMouseDown = true
var pointer = canvas.getPointer(o.e)

var points = [pointer.x, pointer.y, pointer.x, pointer.y]
canvas.remove(this.currentLine)
this.currentLine = new fabric.Line(points, {
strokeWidth: this.strokeWidth,
fill: this.strokeColor,
stroke: this.strokeColor,
originX: "center",
originY: "center",
selectable: false,
evented: false,
})
if (_clicked === 0) {
canvas.add(this.currentLine)
}

if (_start && _clicked === 0) {
// Initialize pathString
this._pathString += `${pointer.x} ${pointer.y} `
this.startCircle = new fabric.Circle({
left: pointer.x,
top: pointer.y,
originX: "center",
originY: "center",
strokeWidth: this.strokeWidth,
stroke: this.strokeColor,
fill: this.strokeColor,
selectable: false,
evented: false,
radius: this.strokeWidth,
})
canvas.add(this.startCircle)

_start = false
} else {
canvas.remove(this.currentPath)
if (_clicked === 0) {
// Update pathString
this._pathString += `L ${pointer.x} `
this._pathString += `${pointer.y} `
}
if (_clicked === 2) {
// Close pathString
this._pathString += "z"
canvas.remove(this.startCircle)
}
}
this.currentPath = new fabric.Path(this._pathString, {
strokeWidth: this.strokeWidth,
fill: this.fillColor,
stroke: this.strokeColor,
originX: "center",
originY: "center",
selectable: false,
evented: false,
})
if (this.currentPath.width !== 0 && this.currentPath.height !== 0) {
canvas.add(this.currentPath)
}
andfanilo marked this conversation as resolved.
Show resolved Hide resolved
if (_clicked === 2) {
this._pathString = "M "
}
}

onMouseMove(o: any) {
if (!this.isMouseDown) return
let canvas = this._canvas
var pointer = canvas.getPointer(o.e)
this.currentLine.set({ x2: pointer.x, y2: pointer.y })
this.currentLine.setCoords()
canvas.renderAll()
}

onMouseUp(o: any) {
this.isMouseDown = true
}

onMouseOut(o: any) {
this.isMouseDown = false
}

onMouseDoubleClick(o: any) {
let canvas = this._canvas
// Double click adds two more points at the end, so we have to move back twice more...
for (let i = 0; i < 3; i++) {
let _last_pt_idx = this._pathString.lastIndexOf("L")
if (_last_pt_idx === -1) {
this._pathString = "M "
canvas.remove(this.startCircle)
} else {
this._pathString = this._pathString.slice(0, _last_pt_idx)
}
}

canvas.remove(this.currentLine)
canvas.remove(this.currentPath)
this.currentPath = new fabric.Path(this._pathString, {
strokeWidth: this.strokeWidth,
fill: this.fillColor,
stroke: this.strokeColor,
originX: "center",
originY: "center",
selectable: false,
evented: false,
})
canvas.add(this.currentPath)
}
}
export default PolypathTool
9 changes: 6 additions & 3 deletions streamlit_drawable_canvas/frontend/src/lib/rect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class RectTool extends FabricTool {

onMouseDown(o: any) {
let canvas = this._canvas
let _clicked = o.e["button"]
this.isMouseDown = true
let pointer = canvas.getPointer(o.e)
this.currentStartX = pointer.x
Expand All @@ -48,8 +49,8 @@ class RectTool extends FabricTool {
top: this.currentStartY,
originX: "left",
originY: "top",
width: pointer.x - this.currentStartX,
height: pointer.y - this.currentStartY,
width: this._minLength,
height: this._minLength,
andfanilo marked this conversation as resolved.
Show resolved Hide resolved
stroke: this.strokeColor,
strokeWidth: this.strokeWidth,
fill: this.fillColor,
Expand All @@ -60,7 +61,9 @@ class RectTool extends FabricTool {
noScaleCache: false,
angle: 0,
})
canvas.add(this.currentRect)
if (_clicked === 0) {
canvas.add(this.currentRect)
}
}

onMouseMove(o: any) {
Expand Down