diff --git a/package-lock.json b/package-lock.json
index fc8b6f3..f3a2101 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
"autoprefixer": "^10.4.20",
"fabric": "^6.1.0",
"postcss-cli": "^11.0.0",
+ "re-resizable": "^6.9.17",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-query": "^3.39.3",
@@ -16756,6 +16757,15 @@
"react-dom": ">=16.9.0"
}
},
+ "node_modules/re-resizable": {
+ "version": "6.9.17",
+ "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.9.17.tgz",
+ "integrity": "sha512-OBqd1BwVXpEJJn/yYROG+CbeqIDBWIp6wathlpB0kzZWWZIY1gPTsgK2yJEui5hOvkCdC2mcexF2V3DZVfLq2g==",
+ "peerDependencies": {
+ "react": "^16.13.1 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
diff --git a/package.json b/package.json
index e1ea614..b7c54e3 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"autoprefixer": "^10.4.20",
"fabric": "^6.1.0",
"postcss-cli": "^11.0.0",
+ "re-resizable": "^6.9.17",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-query": "^3.39.3",
diff --git a/src/App.js b/src/App.js
index 70e2331..9cb75f1 100644
--- a/src/App.js
+++ b/src/App.js
@@ -5,7 +5,7 @@ import { LayoutFilled, ProductFilled, CloudUploadOutlined } from "@ant-design/ic
import Sidebar from './sidebar/sidebar'
import WidgetsContainer from './sidebar/widgetsContainer'
import UploadsContainer from './sidebar/uploadsContainer'
-import Canvas from './canvas/mainClass'
+import Canvas from './canvas/canvas'
function App() {
diff --git a/src/canvas/canvas.js b/src/canvas/canvas.js
new file mode 100644
index 0000000..3e6ccd4
--- /dev/null
+++ b/src/canvas/canvas.js
@@ -0,0 +1,269 @@
+import React from "react"
+import * as fabric from 'fabric'
+import { FullscreenOutlined, ReloadOutlined } from "@ant-design/icons"
+import { Button, Tooltip } from "antd"
+
+import Widget from "./widgets/base"
+import Cursor from "./constants/cursor"
+
+
+class Canvas extends React.Component {
+
+ constructor(props) {
+ super(props)
+
+ this.canvasRef = React.createRef()
+ this.canvasContainerRef = React.createRef()
+
+ /**
+ * @type {Widget[]}
+ */
+ this.widgets = []
+
+ this.modes = {
+ DEFAULT: '',
+ PAN: 'pan',
+ }
+ this.currentMode = this.modes.DEFAULT
+
+ this.mousePressed = false
+ this.mousePos = {
+ x: 0,
+ y: 0
+ }
+
+ this.state = {
+ widgets: [],
+ zoom: 1,
+ isPanning: false,
+ currentTranslate: { x: 0, y: 0 },
+ }
+
+ this.resetTransforms = this.resetTransforms.bind(this)
+
+ // this.updateCanvasDimensions = this.updateCanvasDimensions.bind(this)
+ }
+
+ componentDidMount() {
+ this.initEvents()
+
+ // this.widgets.push(new Widget())
+
+ this.setState({widgets: [new Widget()]})
+
+ }
+
+ componentWillUnmount() {
+
+ }
+
+ mouseDownEvent(event){
+
+ this.mousePressed = true
+
+ this.mousePos.x = event.e.clientX
+ this.mousePos.y = event.e.clientY
+
+ }
+
+ mouseMoveEvent(event){
+
+ }
+
+ mouseUpEvent(event){
+ this.mousePressed = false
+ }
+
+ /**
+ *
+ * @returns {import("./widgets/base").Widget[]}
+ */
+ getWidgets(){
+
+ return this.state.widgets
+ }
+
+ /**
+ * returns list of active objects on the canvas
+ * @returns Widget[]
+ */
+ getActiveObjects(){
+
+ return this.getWidgets().filter((widget) => {
+ return widget.isSelected
+ })
+
+ }
+
+ initEvents(){
+
+ this.canvasContainerRef.current.addEventListener("mousedown", (event) => {
+ this.mousePressed = true
+ this.mousePos = { x: event.clientX, y: event.clientY }
+
+ if (this.state.widgets.length > 0){
+
+ this.currentMode = this.modes.PAN
+ this.setCursor(Cursor.GRAB)
+
+ }
+
+ })
+
+ this.canvasContainerRef.current.addEventListener("mouseup", () => {
+ this.mousePressed = false
+ this.currentMode = this.modes.DEFAULT
+ this.setCursor(Cursor.DEFAULT)
+ })
+
+ this.canvasContainerRef.current.addEventListener("mousemove", (event) => {
+ // console.log("event: ", event)
+ if (this.mousePressed && this.currentMode === this.modes.PAN) {
+ const deltaX = event.clientX - this.mousePos.x
+ const deltaY = event.clientY - this.mousePos.y
+
+ this.setState(prevState => ({
+ currentTranslate: {
+ x: prevState.currentTranslate.x + deltaX,
+ y: prevState.currentTranslate.y + deltaY,
+ }
+ }), this.applyTransform)
+
+ this.mousePos = { x: event.clientX, y: event.clientY }
+
+ this.setCursor(Cursor.GRAB)
+ }
+
+
+
+ })
+
+ this.canvasContainerRef.current.addEventListener("selection:created", () => {
+ console.log("selected")
+ this.currentMode = this.modes.DEFAULT
+ })
+
+ this.canvasContainerRef.current.addEventListener('wheel', (event) => {
+ this.wheelZoom(event)
+ })
+
+ }
+
+ applyTransform(){
+ const { currentTranslate, zoom } = this.state
+ this.canvasRef.current.style.transform = `translate(${currentTranslate.x}px, ${currentTranslate.y}px) scale(${zoom})`
+ }
+
+ wheelZoom(event){
+ let delta = event.deltaY
+ let zoom = this.state.zoom * 0.999 ** delta
+ this.setZoom(zoom, {x: event.offsetX, y: event.offsetY})
+ }
+
+ /**
+ * fits the canvas size to fit the widgets bounding box
+ */
+ fitCanvasToBoundingBox(){
+ // this.canvasRef.current.style.width = this.canvasContainerRef.current.clientWidth
+ // this.canvasRef.current.style.height = this.canvasContainerRef.current.clientHeight
+ }
+
+ setCursor(cursor){
+ this.canvasContainerRef.current.style.cursor = cursor
+ }
+
+ setZoom(zoom, pos={x:0, y:0}){
+
+ const { currentTranslate } = this.state
+
+ // Calculate the new translation to zoom into the mouse position
+ const offsetX = pos.x - (this.canvasContainerRef.current.clientWidth / 2 + currentTranslate.x)
+ const offsetY = pos.y - (this.canvasContainerRef.current.clientHeight / 2 + currentTranslate.y)
+
+ const newTranslateX = currentTranslate.x - offsetX * (zoom - this.state.zoom)
+ const newTranslateY = currentTranslate.y - offsetY * (zoom - this.state.zoom)
+
+ this.setState({
+ zoom: zoom,
+ currentTranslate: {
+ x: newTranslateX,
+ y: newTranslateY
+ }
+ }, this.applyTransform)
+
+ }
+
+ getCanvasObjectsBoundingBox(padding = 0) {
+ const objects = this.fabricCanvas.getObjects()
+ if (objects.length === 0) {
+ return { left: 0, top: 0, width: this.fabricCanvas.width, height: this.fabricCanvas.height }
+ }
+
+ const boundingBox = objects.reduce((acc, obj) => {
+ const objBoundingBox = obj.getBoundingRect(true)
+ acc.left = Math.min(acc.left, objBoundingBox.left)
+ acc.top = Math.min(acc.top, objBoundingBox.top)
+ acc.right = Math.max(acc.right, objBoundingBox.left + objBoundingBox.width)
+ acc.bottom = Math.max(acc.bottom, objBoundingBox.top + objBoundingBox.height)
+ return acc
+ }, {
+ left: Infinity,
+ top: Infinity,
+ right: -Infinity,
+ bottom: -Infinity
+ })
+
+ // Adding padding
+ boundingBox.left -= padding
+ boundingBox.top -= padding
+ boundingBox.right += padding
+ boundingBox.bottom += padding
+
+ return {
+ left: boundingBox.left,
+ top: boundingBox.top,
+ width: boundingBox.right - boundingBox.left,
+ height: boundingBox.bottom - boundingBox.top
+ }
+ }
+
+ resetTransforms() {
+ this.setState({
+ zoom: 1,
+ currentTranslate: { x: 0, y: 0 }
+ }, this.applyTransform)
+ }
+
+ render() {
+ return (
+
+
+
+
+
+ } onClick={this.resetTransforms} />
+
+
+
+
+
+
+ {
+ this.state.widgets.map((wid, index) => {
+ return {React.cloneElement(wid, {ref:wid.elementRef})}
+ })
+ }
+
+
+
+
+ )
+ }
+}
+
+export default Canvas
diff --git a/src/canvas/constants/cursor.js b/src/canvas/constants/cursor.js
new file mode 100644
index 0000000..b99a07a
--- /dev/null
+++ b/src/canvas/constants/cursor.js
@@ -0,0 +1,16 @@
+
+const Cursor = {
+ POINTER: 'pointer',
+ DEFAULT: 'default',
+ CROSSHAIR: 'crosshair',
+ EW_RESIZE: 'e-resize', // east resize
+ NS_RESIZE: 'n-resize', // east resize
+ NW_RESIZE: 'nw-resize', // east resize
+ SE_RESIZE: 'se-resize',
+ SW_RESIZE: 'sw-resize',
+ GRAB: 'grab',
+ GRABBING: 'grabbing',
+}
+
+
+export default Cursor
\ No newline at end of file
diff --git a/src/canvas/constants/layouts.js b/src/canvas/constants/layouts.js
new file mode 100644
index 0000000..82db7bd
--- /dev/null
+++ b/src/canvas/constants/layouts.js
@@ -0,0 +1,7 @@
+const Layouts = {
+ PACK: "flex",
+ GRID: "grid",
+ PLACE: "absolute"
+}
+
+export default Layouts
\ No newline at end of file
diff --git a/src/canvas/constants/tools.js b/src/canvas/constants/tools.js
new file mode 100644
index 0000000..486300a
--- /dev/null
+++ b/src/canvas/constants/tools.js
@@ -0,0 +1,8 @@
+
+const Tools = {
+ COLOR_PICKER: "color_picker",
+ EVENT_HANDLER: "event_handler", // shows a event handler with all the possible function in the dropdown
+}
+
+
+export default Tools
\ No newline at end of file
diff --git a/src/canvas/fabricCanvas.js b/src/canvas/fabricCanvas.js
deleted file mode 100644
index b743ee1..0000000
--- a/src/canvas/fabricCanvas.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import React, { useCallback, useEffect, useRef, useState } from 'react'
-import * as fabric from 'fabric'
-
-/**
- * NOTE: Not in use
- */
-function FabricJSCanvas({ canvasOptions, className = '', onCanvasContextUpdate }) {
-
- const canvasRef = useRef(null)
-
- const fabricCanvasRef = useRef(null)
-
- useEffect(() => {
-
- const options = {}
- let canvas = null
- if (canvasRef.current) {
- canvas = new fabric.Canvas(canvasRef.current, options)
- const parent = canvasRef.current.parentNode.parentNode
- canvas.setDimensions({ width: parent.clientWidth, height: parent.clientHeight })
- canvas.calcOffset()
-
- fabricCanvasRef.current = canvas
- canvasRef.current.parentNode.style.width = "100%"
- canvasRef.current.parentNode.style.height = "100%"
-
- console.log("Parent: ", canvasRef.current.parentNode.parentNode)
-
- canvasRef.current.parentNode.parentNode.addEventListener("resize", updateCanvasDimensions)
- window.addEventListener("resize", updateCanvasDimensions)
-
- // make the fabric.Canvas instance available to your app
- if (onCanvasContextUpdate)
- onCanvasContextUpdate(canvas)
- }
-
- return () => {
- window.removeEventListener("resize", updateCanvasDimensions)
- canvasRef.current.parentNode.parentNode.removeEventListener("resize", updateCanvasDimensions)
-
- if (onCanvasContextUpdate)
- onCanvasContextUpdate(null)
-
- canvas.dispose()
- }
- }, [canvasRef])
-
-
- const updateCanvasDimensions = useCallback(() => {
- if (!canvasRef.current || !fabricCanvasRef.current)
- return
- // console.log("Updating canvas")
- const parent = canvasRef.current.parentNode.parentNode
-
- fabricCanvasRef.current.setDimensions({ width: parent.clientWidth, height: parent.clientHeight })
- fabricCanvasRef.current.calcOffset()
-
- fabricCanvasRef.current.renderAll()
-
- }, [fabricCanvasRef, canvasRef])
-
-
-
- return