From c3759e0457b2b1dc75071caf1a5037949ab6653c Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 18 Sep 2024 11:39:07 +0530 Subject: [PATCH] moved resize handler from widget to canvas, canvas handles resizing --- src/canvas/canvas.js | 120 ++++++++++++++++++------ src/canvas/widgets/base.js | 182 +++++++++++++++++++------------------ src/styles/index.css | 10 ++ 3 files changed, 198 insertions(+), 114 deletions(-) diff --git a/src/canvas/canvas.js b/src/canvas/canvas.js index 8cae889..ef9ea9d 100644 --- a/src/canvas/canvas.js +++ b/src/canvas/canvas.js @@ -61,14 +61,15 @@ class Canvas extends React.Component { this.widgetRefs = {} // stores the actual refs to the widgets inside the canvas {id: ref, id2, ref2...} this.state = { - widgets: [], // stores the mapping to widgetRefs, stores id and WidgetType, later used for rendering [{id: , widgetType: WidgetClass}] + widgetResizing: "", // set this to "nw", "sw" etc based on the side when widgets resizing handles are selected + widgets: [], // stores the mapping to widgetRefs, stores id and WidgetType, later used for rendering [{id: , widgetType: WidgetClass, children: [], parent: ""}] zoom: 1, isPanning: false, currentTranslate: { x: 0, y: 0 }, canvasSize: { width: 500, height: 500 }, contextMenuItems: [], - selectedWidgets: [], + selectedWidget: null, toolbarOpen: true, toolbarAttrs: null @@ -209,20 +210,17 @@ class Canvas extends React.Component { if (selectedWidget){ // if the widget is selected don't pan, instead move the widget if (!selectedWidget._disableSelection){ - - const selectedLength = this.state.selectedWidgets.length - // console.log("selected widget: ", selectedWidget) - if (selectedLength === 0 || (selectedLength === 1 && selectedWidget.__id !== this.state.selectedWidgets[0].__id)){ - this.state.selectedWidgets[0]?.deSelect() // deselect the previous widget before adding the new one - this.state.selectedWidgets[0]?.setZIndex(0) + if (!this.state.selectedWidget || (selectedWidget.__id !== this.state.selectedWidget?.__id)){ + this.state.selectedWidget?.deSelect() // deselect the previous widget before adding the new one + this.state.selectedWidget?.setZIndex(0) selectedWidget.setZIndex(1000) selectedWidget.select() this.setState({ - selectedWidgets: [selectedWidget], + selectedWidget: selectedWidget, toolbarAttrs: selectedWidget.getToolbarAttrs() }) @@ -240,7 +238,7 @@ class Canvas extends React.Component { this.clearSelections() this.currentMode = CanvasModes.PAN this.setCursor(Cursor.GRAB) - + console.log("clear selection") } this.setState({ @@ -253,14 +251,14 @@ class Canvas extends React.Component { }else if (event.button === 2){ //right click - if (this.state.selectedWidgets.length > 0 && this.state.selectedWidgets[0].__id !== selectedWidget.__id){ + if (this.state.selectedWidget && this.state.selectedWidget.__id !== selectedWidget.__id){ this.clearSelections() } if (selectedWidget){ this.setState({ - selectedWidget: [selectedWidget], + selectedWidget: selectedWidget, contextMenuItems: [ { key: "rename", @@ -284,12 +282,18 @@ class Canvas extends React.Component { mouseMoveEvent(event){ + if (this.state.widgetResizing !== ""){ + // if resizing is taking place don't do anything else + this.handleResize(event) + return + } + // console.log("mode: ", this.currentMode, this.getActiveObjects()) if (this.mousePressed && [CanvasModes.PAN, CanvasModes.MOVE_WIDGET].includes(this.currentMode)) { const deltaX = event.clientX - this.mousePos.x const deltaY = event.clientY - this.mousePos.y - if (this.state.selectedWidgets.length === 0){ + if (!this.state.selectedWidget){ // if there aren't any selected widgets, then pan the canvas this.setState(prevState => ({ currentTranslate: { @@ -320,6 +324,10 @@ class Canvas extends React.Component { this.mousePressed = false this.currentMode = CanvasModes.DEFAULT this.setCursor(Cursor.DEFAULT) + + if (this.state.widgetResizing) { + this.setState({ widgetResizing: "" }) + } } wheelZoom(event){ @@ -329,6 +337,59 @@ class Canvas extends React.Component { this.setZoom(zoom, {x: event.offsetX, y: event.offsetY}) } + /** + * handles widgets resizing + * @param {MouseEvent} event - mouse move event + * @returns + */ + handleResize = (event) => { + if (this.state.resizing === "") return + + const widget = this.state.selectedWidget + + if (!widget) return + const resizeCorner = this.state.widgetResizing + const size = widget.getSize() + const pos = widget.getPos() + + const deltaX = event.movementX + const deltaY = event.movementY + + let newSize = { ...size } + let newPos = { ...pos } + + const { width: minWidth, height: minHeight } = widget.minSize + const { width: maxWidth, height: maxHeight } = widget.maxSize + // console.log("resizing: ", deltaX, deltaY, event) + + switch (resizeCorner) { + case "nw": + newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width - deltaX)) + newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height - deltaY)) + newPos.x += (newSize.width !== size.width) ? deltaX : 0 + newPos.y += (newSize.height !== size.height) ? deltaY : 0 + break + case "ne": + newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width + deltaX)) + newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height - deltaY)) + newPos.y += (newSize.height !== size.height) ? deltaY : 0 + break + case "sw": + newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width - deltaX)) + newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height + deltaY)) + newPos.x += (newSize.width !== size.width) ? deltaX : 0 + break + case "se": + newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width + deltaX)) + newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height + deltaY)) + break + default: + break + } + + widget.setResize(newPos, newSize) + } + getCanvasContainerBoundingRect(){ return this.canvasContainerRef.current.getBoundingClientRect() } @@ -411,6 +472,10 @@ class Canvas extends React.Component { } clearSelections(){ + + if (!this.state.selectedWidget) + return + this.getActiveObjects().forEach(widget => { widget.current?.deSelect() }) @@ -419,7 +484,7 @@ class Canvas extends React.Component { // this.context.updateToolAttrs({}) this.setState({ - selectedWidgets: [], + selectedWidget: null, toolbarAttrs: null, // toolbarOpen: }) @@ -462,7 +527,8 @@ class Canvas extends React.Component { // Store the ref in the instance variable this.widgetRefs[id] = widgetRef - const widgets = [...this.state.widgets, { id, widgetType: widgetComponentType }] // don't add the widget refs in the state + const widgets = [...this.state.widgets, { id, widgetType: widgetComponentType, children: [], parent: "" }] // don't add the widget refs in the state + // Update the state to include the new widget's type and ID this.setState({ widgets: widgets @@ -491,7 +557,7 @@ class Canvas extends React.Component { deleteSelectedWidgets(widgets=[]){ - let activeWidgets = removeDuplicateObjects([...widgets, ...this.state.selectedWidgets], "__id") + let activeWidgets = removeDuplicateObjects([...widgets, this.state.selectedWidget], "__id") const widgetIds = activeWidgets.map(widget => widget.__id) @@ -520,11 +586,6 @@ class Canvas extends React.Component { clearCanvas(){ // NOTE: Don't remove from it using remove() function since, it already removed from the DOM tree when its removed from widgets - // for (let [key, value] of Object.entries(this.widgetRefs)){ - // console.log("removed: ", value, value.current?.getElement()) - - // value.current?.remove() - // } this.widgetRefs = {} this.setState({ @@ -552,15 +613,15 @@ class Canvas extends React.Component { onActiveWidgetUpdate(widgetId){ - if (this.state.selectedWidgets.length === 0 || widgetId !== this.state.selectedWidgets[0].__id) + if (!this.state.selectedWidget || widgetId !== this.state.selectedWidget.__id) return - console.log("updating...", this.state.toolbarAttrs, this.state.selectedWidgets.at(0).getToolbarAttrs()) + // console.log("updating...", this.state.toolbarAttrs, this.state.selectedWidget.getToolbarAttrs()) // console.log("attrs: ", this.state.selectedWidgets.at(0).getToolbarAttrs()) this.setState({ - toolbarAttrs: this.state.selectedWidgets.at(0).getToolbarAttrs() + toolbarAttrs: this.state.selectedWidget.getToolbarAttrs() }) } @@ -601,12 +662,15 @@ class Canvas extends React.Component { } renderWidget(widget){ - const { id, widgetType: ComponentType } = widget + const { id, widgetType: ComponentType, children=[], parent } = widget // console.log("widet: ", this.widgetRefs, id) - + // TODO: need to pass the widget ref for child elements as well return this.setState({widgetResizing: resizeSide })} /> } @@ -631,7 +695,7 @@ class Canvas extends React.Component { onDrop={this.handleDropEvent}> {/* */} -
{/* */} diff --git a/src/canvas/widgets/base.js b/src/canvas/widgets/base.js index 3a85939..52f8fc1 100644 --- a/src/canvas/widgets/base.js +++ b/src/canvas/widgets/base.js @@ -142,24 +142,24 @@ class Widget extends React.Component { this.setWidgetStyling = this.setWidgetStyling.bind(this) - this.startResizing = this.startResizing.bind(this) - this.handleResize = this.handleResize.bind(this) - this.stopResizing = this.stopResizing.bind(this) + // this.startResizing = this.startResizing.bind(this) + // this.handleResize = this.handleResize.bind(this) + // this.stopResizing = this.stopResizing.bind(this) } componentDidMount() { this.elementRef.current?.addEventListener("click", this.mousePress) - this.canvas.addEventListener("mousemove", this.handleResize) - this.canvas.addEventListener("mouseup", this.stopResizing) + // this.canvas.addEventListener("mousemove", this.handleResize) + // this.canvas.addEventListener("mouseup", this.stopResizing) } componentWillUnmount() { this.elementRef.current?.removeEventListener("click", this.mousePress) - this.canvas.addEventListener("mousemove", this.handleResize) - this.canvas.addEventListener("mouseup", this.stopResizing) + // this.canvas.addEventListener("mousemove", this.handleResize) + // this.canvas.addEventListener("mouseup", this.stopResizing) } componentDidUpdate(prevProps, prevState) { @@ -287,10 +287,10 @@ class Widget extends React.Component { setPos(x, y) { - if (this.state.resizing) { - // don't change position when resizing the widget - return - } + // if (this.state.resizing) { + // // don't change position when resizing the widget + // return + // } this.setState({ pos: { x, y } @@ -301,19 +301,6 @@ class Widget extends React.Component { // }) } - setParent(parentId) { - this._parent = parentId - } - - addChild(childId) { - this._children.push(childId) - } - - removeChild(childId) { - this._children = this._children.filter(function (item) { - return item !== childId - }) - } getPos() { return this.state.pos @@ -368,11 +355,6 @@ class Widget extends React.Component { }) } - startResizing(corner, event) { - event.stopPropagation() - this.setState({ resizing: true, resizeCorner: corner }) - } - setZIndex(zIndex) { this.setState({ zIndex: zIndex @@ -381,10 +363,6 @@ class Widget extends React.Component { setWidgetName(name) { - // this.setState((prev) => ({ - // widgetName: name.length > 0 ? name : prev.widgetName - // })) - this.updateState({ widgetName: name.length > 0 ? name : this.state.widgetName }) @@ -394,7 +372,6 @@ class Widget extends React.Component { * * @param {string} key - The string in react Style format * @param {string} value - Value of the style - * @param {function():void} [callback] - optional callback, thats called after setting the internal state */ setWidgetStyling(key, value) { @@ -425,57 +402,70 @@ class Widget extends React.Component { }) } - handleResize(event) { - if (!this.state.resizing) return - - const { resizeCorner, size, pos } = this.state - const deltaX = event.movementX - const deltaY = event.movementY - - let newSize = { ...size } - let newPos = { ...pos } - - const { width: minWidth, height: minHeight } = this.minSize - const { width: maxWidth, height: maxHeight } = this.maxSize - // console.log("resizing: ", deltaX, deltaY, event) - - switch (resizeCorner) { - case "nw": - newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width - deltaX)) - newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height - deltaY)) - newPos.x += (newSize.width !== size.width) ? deltaX : 0 - newPos.y += (newSize.height !== size.height) ? deltaY : 0 - break - case "ne": - newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width + deltaX)) - newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height - deltaY)) - newPos.y += (newSize.height !== size.height) ? deltaY : 0 - break - case "sw": - newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width - deltaX)) - newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height + deltaY)) - newPos.x += (newSize.width !== size.width) ? deltaX : 0 - break - case "se": - newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width + deltaX)) - newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height + deltaY)) - break - default: - break - } - - // this.setState({ size: newSize, pos: newPos }) + setResize(pos, size){ + // useful when resizing the widget relative to the canvas, sets all pos, and size this.updateState({ - size: newSize, - pos: newPos + size: size, + pos: pos }) } - stopResizing() { - if (this.state.resizing) { - this.setState({ resizing: false }) - } - } + // startResizing(corner, event) { + // event.stopPropagation() + // this.setState({ resizing: true, resizeCorner: corner }) + // } + + // handleResize(event) { + // if (!this.state.resizing) return + + // const { resizeCorner, size, pos } = this.state + // const deltaX = event.movementX + // const deltaY = event.movementY + + // let newSize = { ...size } + // let newPos = { ...pos } + + // const { width: minWidth, height: minHeight } = this.minSize + // const { width: maxWidth, height: maxHeight } = this.maxSize + // // console.log("resizing: ", deltaX, deltaY, event) + + // switch (resizeCorner) { + // case "nw": + // newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width - deltaX)) + // newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height - deltaY)) + // newPos.x += (newSize.width !== size.width) ? deltaX : 0 + // newPos.y += (newSize.height !== size.height) ? deltaY : 0 + // break + // case "ne": + // newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width + deltaX)) + // newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height - deltaY)) + // newPos.y += (newSize.height !== size.height) ? deltaY : 0 + // break + // case "sw": + // newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width - deltaX)) + // newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height + deltaY)) + // newPos.x += (newSize.width !== size.width) ? deltaX : 0 + // break + // case "se": + // newSize.width = Math.max(minWidth, Math.min(maxWidth, newSize.width + deltaX)) + // newSize.height = Math.max(minHeight, Math.min(maxHeight, newSize.height + deltaY)) + // break + // default: + // break + // } + + // // this.setState({ size: newSize, pos: newPos }) + // this.updateState({ + // size: newSize, + // pos: newPos + // }) + // } + + // stopResizing() { + // if (this.state.resizing) { + // this.setState({ resizing: false }) + // } + // } openRenaming() { this.setState({ @@ -490,6 +480,22 @@ class Widget extends React.Component { }) } + setParent(parentId) { + this._parent = parentId + } + + addChild(childWidget) { + + childWidget.setParent(this.__id) + this._children.push(childWidget) + } + + removeChild(childId) { + this._children = this._children.filter(function (item) { + return item !== childId + }) + } + handleDrop = (event, dragElement) => { console.log("dragging event: ", event, dragElement) @@ -509,7 +515,7 @@ class Widget extends React.Component { // throw new NotImplementedError("render method has to be implemented") return (
- + {/* {this.props.children} */}
) } @@ -598,7 +604,8 @@ class Widget extends React.Component { className="tw-w-2 tw-h-2 tw-absolute tw--left-1 tw--top-1 tw-bg-blue-500" style={{ cursor: Cursor.NW_RESIZE }} onMouseDown={(e) => { - this.startResizing("nw", e) + // this.startResizing("nw", e) + this.props.onWidgetResizing("nw") this.setState({dragEnabled: false}) }} onMouseLeave={() => this.setState({dragEnabled: true})} @@ -607,7 +614,8 @@ class Widget extends React.Component { className="tw-w-2 tw-h-2 tw-absolute tw--right-1 tw--top-1 tw-bg-blue-500" style={{ cursor: Cursor.SW_RESIZE }} onMouseDown={(e) => { - this.startResizing("ne", e) + // this.startResizing("ne", e) + this.props.onWidgetResizing("ne") this.setState({dragEnabled: false}) }} onMouseLeave={() => this.setState({dragEnabled: true})} @@ -616,7 +624,8 @@ class Widget extends React.Component { className="tw-w-2 tw-h-2 tw-absolute tw--left-1 tw--bottom-1 tw-bg-blue-500" style={{ cursor: Cursor.SW_RESIZE }} onMouseDown={(e) => { - this.startResizing("sw", e) + // this.startResizing("sw", e) + this.props.onWidgetResizing("sw") this.setState({dragEnabled: false}) }} onMouseLeave={() => this.setState({dragEnabled: true})} @@ -625,7 +634,8 @@ class Widget extends React.Component { className="tw-w-2 tw-h-2 tw-absolute tw--right-1 tw--bottom-1 tw-bg-blue-500" style={{ cursor: Cursor.SE_RESIZE }} onMouseDown={(e) => { - this.startResizing("se", e) + // this.startResizing("se", e) + this.props.onWidgetResizing("se") this.setState({dragEnabled: false}) }} onMouseLeave={() => this.setState({dragEnabled: true})} diff --git a/src/styles/index.css b/src/styles/index.css index 961219b..c3c03fa 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -17,6 +17,16 @@ body { background-size: cover; } +.stripes-bg { + width: 100%; + height: 100%; + --color: #E1E1E1; + background-color: #F3F3F3; + background-image: linear-gradient(0deg, transparent 24%, var(--color) 25%, var(--color) 26%, transparent 27%,transparent 74%, var(--color) 75%, var(--color) 76%, transparent 77%,transparent), + linear-gradient(90deg, transparent 24%, var(--color) 25%, var(--color) 26%, transparent 27%,transparent 74%, var(--color) 75%, var(--color) 76%, transparent 77%,transparent); + background-size: 55px 55px; + } + .input{ border: 2px solid #e3e5e8; padding: 2px 8px;