diff --git a/.gitignore b/.gitignore index e4508357c..f70cb4297 100644 --- a/.gitignore +++ b/.gitignore @@ -37,12 +37,9 @@ cabal.sandbox.config .pnpm-store/ # TODO: eventually remove all public/js files from tracking -/public/js/search /public/js/grid/app.js -/public/js/post/app.js /public/js/generate/app.js /public/js/graph/app.js -/public/js/draw/app.js /public/js/about/app.js /public/*.svg /public/*.png diff --git a/.prettierignore b/.prettierignore index 716179648..eff884640 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,9 +3,6 @@ db/ doc/ graphs/ -# TODO: review this file -js/components/draw/ - public/ vendor/ diff --git a/CHANGELOG.md b/CHANGELOG.md index ea7751191..6d2b1db65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - Added invalid JSON graph test coverage for `saveGraphJSON` in `app/Controllers/Graph.hs` - Converted various JS files to TypeScript - Fixed lint-staged check for CSS files +- Removed deprecated `Draw` feature and remaining references to previously deprecated `Search` and `Post` features ## [0.8.1] - 2026-08-10 diff --git a/app/MasterTemplate.hs b/app/MasterTemplate.hs index 78f9b845e..bf656c5a5 100644 --- a/app/MasterTemplate.hs +++ b/app/MasterTemplate.hs @@ -52,10 +52,6 @@ header page = if page == "generate-prerequisites" then H.li ! A.class_ "selected-page" $ toLink "/generate" "Generate (beta)" else H.li ! A.id "nav-generate" $ toLink "/generate" "Generate (beta)" - -- H.li $ toLink "/timesearch" "Search" - -- H.li $ toLink "/draw" "Draw" - -- TODO: re-enable after handling new first-year courses - -- H.li $ toLink "post" "Check My POSt!" if page == "about" then H.li ! A.class_ "selected-page" $ toLink "/about" "About" else H.li $ toLink "/about" "About" diff --git a/app/Response.hs b/app/Response.hs index ce3d9c92a..bd3e3f8f0 100644 --- a/app/Response.hs +++ b/app/Response.hs @@ -1,6 +1,5 @@ module Response (module X) where import Response.About as X -import Response.Draw as X import Response.Loading as X import Response.NotFound as X diff --git a/app/Response/Draw.hs b/app/Response/Draw.hs deleted file mode 100644 index 7d0d0d763..000000000 --- a/app/Response/Draw.hs +++ /dev/null @@ -1,65 +0,0 @@ -module Response.Draw (drawResponse) where - -import Control.Monad (forM_) -import Happstack.Server -import MasterTemplate -import Scripts -import Text.Blaze ((!)) -import qualified Text.Blaze.Html5 as H -import qualified Text.Blaze.Html5.Attributes as A - -drawResponse :: ServerPart Response -drawResponse = - ok $ - toResponse $ - masterTemplate - "Courseography - Draw!" - [] - ( do - header "draw" - drawContent - modePanel - H.div ! A.id "react-graph" $ "" - ) - drawScripts - -drawContent :: H.Html -drawContent = H.div ! A.id "about-div" $ "Draw a Graph" - -modePanel :: H.Html -modePanel = H.div ! A.id "side-panel-wrap" $ do - H.div ! A.id "node-mode" ! A.class_ "mode clicked" $ "NODE (n)" - H.input - ! A.id "course-code" - ! A.class_ "course-code" - ! A.name "course-code" - ! A.placeholder "Course Code" - ! A.autocomplete "off" - ! A.type_ "text" - ! A.size "10" - H.div ! A.id "add-text" ! A.class_ "button" $ "ADD" - H.div ! A.id "path-mode" ! A.class_ "mode" $ "PATH (p)" - H.div ! A.id "region-mode" ! A.class_ "mode" $ "REGION (r)" - H.div ! A.id "finish-region" ! A.class_ "button" $ "finish (f)" - H.div ! A.id "change-mode" ! A.class_ "mode" $ "SELECT/MOVE (m)" - H.div ! A.id "erase-mode" ! A.class_ "mode" $ "ERASE (e)" - H.input - ! A.id "select-colour" - ! A.class_ "jscolor" - ! A.value "ff7878" -- pastelRed color as defined in Css.Constants - ! A.size "15" - H.table ! A.id "colour-table" $ - forM_ - (replicate 2 $ replicate 5 "" :: [[H.Html]]) - (H.tr . mapM_ (H.td . H.toHtml)) - H.div ! A.id "save-graph" ! A.class_ "button" $ "SAVE" - H.input - ! A.id "area-of-study" - ! A.class_ "course-code" - ! A.name "course-code" - ! A.placeholder "Enter area of study." - ! A.autocomplete "off" - ! A.type_ "text" - ! A.size "30" - H.div ! A.id "submit-graph-name" ! A.class_ "button" $ "Search for department" - H.div ! A.id "json-data" ! A.class_ "json-data" $ "" diff --git a/app/Routes.hs b/app/Routes.hs index 7bcd6b900..c8c03290a 100644 --- a/app/Routes.hs +++ b/app/Routes.hs @@ -24,7 +24,7 @@ import Happstack.Server ( seeOther, serveDirectory, ) -import Response (aboutResponse, drawResponse, loadingResponse, notFoundResponse) +import Response (aboutResponse, loadingResponse, notFoundResponse) routeResponses :: String -> ServerPartT IO Response routeResponses staticDir = @@ -45,7 +45,6 @@ strictRoutes = , ("timetable-image", TimetableController.exportTimetableImageResponse) , ("timetable-pdf", TimetableController.exportTimetablePDFResponse) , ("post", ProgramController.retrieveProgram) - , ("draw", drawResponse) , ("about", aboutResponse) , ("graphs", GraphsController.index) , ("generate", generateResponse) diff --git a/app/Scripts.hs b/app/Scripts.hs index ca06054ec..12821ff20 100644 --- a/app/Scripts.hs +++ b/app/Scripts.hs @@ -1,9 +1,6 @@ module Scripts ( graphScripts, timetableScripts, - drawScripts, - postScripts, - searchScripts, generateScripts, aboutScripts, ) @@ -12,7 +9,6 @@ where import Text.Blaze ((!)) import qualified Text.Blaze.Html5 as H import qualified Text.Blaze.Html5.Attributes as A -import Util.Blaze graphScripts :: H.Html graphScripts = H.script ! A.src "/static/js/graph/app.js" $ "" @@ -20,26 +16,6 @@ graphScripts = H.script ! A.src "/static/js/graph/app.js" $ "" timetableScripts :: H.Html timetableScripts = H.script ! A.src "/static/js/grid/app.js" $ "" -drawScripts :: H.Html -drawScripts = do - mapM_ - toScript - [ "/static/js/draw/variables.js" - , "/static/js/draw/path.js" - , "/static/js/draw/setup.js" - , "/static/js/vendor/jscolor.min.js" - ] - H.script ! A.src "/static/js/draw/app.js" $ "" - -postScripts :: H.Html -postScripts = do - mapM_ toScript [] - H.script ! A.src "/static/js/post/app.js" $ "" - -searchScripts :: H.Html -searchScripts = do - H.script ! A.src "/static/js/search/app.js" $ "" - generateScripts :: H.Html generateScripts = do H.script ! A.src "/static/js/generate/app.js" $ "" diff --git a/courseography.cabal b/courseography.cabal index 285b9a212..b9d33023e 100644 --- a/courseography.cabal +++ b/courseography.cabal @@ -201,7 +201,6 @@ executable courseography Models.Time, Response, Response.About, - Response.Draw, Response.Loading, Response.NotFound, Routes, diff --git a/js/components/draw/draw.js b/js/components/draw/draw.js deleted file mode 100644 index a91c27927..000000000 --- a/js/components/draw/draw.js +++ /dev/null @@ -1,668 +0,0 @@ -/** - * Calculates the position of the click in relation to the page. - * @param {object} e The click event. - * @param {HTMLElement} elem The target of the click event. - * @return {object} The position of the click. - */ -function getClickPosition(e, elem) { - "use strict" - - var parentPosition = getPosition(elem) - var xPosition = e.clientX - parentPosition.x - var yPosition = e.clientY - parentPosition.y - xPosition = Math.round(xPosition / 4) * 4 // for snapping!! - yPosition = Math.round(yPosition / 4) * 4 - - return { x: xPosition, y: yPosition } -} - -/** - * Calculates the position of elem in relation to the page. - * @param {HTMLElement} elem The target of the click event. - * @return {object} The position of elem on the page. - */ -function getPosition(elem) { - "use strict" - - var xPosition = 0 - var yPosition = 0 - - while (elem) { - // || 0 for firefox compatability - xPosition += (elem.offsetLeft || 0) - elem.scrollLeft + elem.clientLeft - yPosition += (elem.offsetTop || 0) - elem.scrollTop + elem.clientTop - elem = elem.parentElement // offsetParent undefined in mozilla - } - return { x: xPosition, y: yPosition } -} - -/** - * Creates a new node within the SVG canvas with specific attributes. - * If no attributes are specified, then a generic blank node is created. - * @param {String} posX The x-coordinate of the node. - * @param {String} posY The y-coordinate of the node. - * @param {JSON} jsonObj Specifies the node's attributes. - */ -function makeNode(posX, posY, jsonObj) { - "use strict" - - var textPosX = posX - var textPosY = posY - var textStr = "" - var textFill = "" - var textAlign = "begin" - var textId = "t" + nodeId - - if (jsonObj) { - var nodeWidth = jsonObj.width - var nodeHeight = jsonObj.height - var nodeFill = jsonObj.fill || "none" - var nodeId_ = "n" + jsonObj.id_ - var nodeTolerance = jsonObj.tolerance - - switch (jsonObj.type_) { - case "Hybrid": - var node = document.createElementNS(xmlns, "rect") - var gClass = "hybrid" - textFill = "white" - break - case "BoolNode": - var node = document.createElementNS(xmlns, "ellipse") - var gClass = "bool" - node.setAttribute("stroke", "black") - node.setAttribute("rx", 10) - node.setAttribute("ry", 7) - node.setAttribute("cx", posX) - node.setAttribute("cy", posY) - break - default: - // Node - var node = document.createElementNS(xmlns, "rect") - var gClass = "node" - node.setAttribute("rx", 4) - node.setAttribute("ry", 4) - } - } else { - var nodeWidth = 40 - var nodeHeight = 32 - var nodeFill = "#" + document.getElementById("select-colour").value - var nodeId_ = "n" + nodeId - var nodeTolerance = 9 - - var gClass = "node" - var node = document.createElementNS(xmlns, "rect") - node.setAttribute("rx", 4) - node.setAttribute("ry", 4) - } - - var g = document.createElementNS(xmlns, "g") - - g.setAttribute("class", gClass) - g.setAttribute("id", "g" + nodeId) - g.setAttribute("data-active", "active") - - node.setAttribute("x", posX) - node.setAttribute("y", posY) - node.setAttribute("fill", nodeFill) - node.setAttribute("id", nodeId_) - node.setAttribute("width", nodeWidth) - node.setAttribute("height", nodeHeight) - node.setAttribute("class", "node") - node.setAttribute("tolerance", nodeTolerance) - node.predecessors = [] - node.successors = [] - // note: children doesn't work because javascript objects already have a children attribute - node.inEdges = [] - node.outEdges = [] - - g.appendChild(node) - document.getElementById("nodes").appendChild(g) - document - .getElementById(nodeId_) - .addEventListener("mousedown", nodeClicked, false) - - // Input Text into Shape - if (jsonObj) { - for (var i = 0; i < jsonObj.text.length; i++) { - textPosX = jsonObj.pos[0] - if (jsonObj.type_ !== "BoolNode") { - textPosX += jsonObj.width / 2 - } - - textPosY = jsonObj.text[i].pos[1] - jsonObj.height / 4 - textStr = jsonObj.text[i].text || "" - textFill = jsonObj.text[i].fill - textAlign = jsonObj.text[i].align - textId = "t" + jsonObj.id_ - - var code = document.createElementNS(xmlns, "text") - code.setAttributeNS(null, "id", textId) - code.setAttributeNS(null, "fill", textFill) - code.setAttributeNS(null, "align", textAlign) - code.setAttributeNS(null, "x", textPosX) - code.setAttributeNS(null, "y", textPosY) - code.setAttributeNS(null, "class", "mylabel") // note: label is a class in bootstrap - var textNode = document.createTextNode(textStr) - code.appendChild(textNode) - g.appendChild(code) - document - .getElementById(textId) - .addEventListener("mousedown", nodeClicked, false) - } - } - select(document.getElementById(nodeId_)) - nodeId += 1 -} - -/** - * In node-mode creates a new node at the position of the click event on the SVG canvas. - * In path-mode creates an elbow at the position of the click event on the SVG canvas, - if the startNode is defined. - * @param {object} e The mousedown event. - */ -export function makeNodePath(e) { - "use strict" - var position = getClickPosition(e, e.currentTarget) - if (mode === "node-mode") { - makeNode(position.x, position.y) - } else if (mode === "path-mode") { - // make elbow joint, only if the dummy point is outside the starting node - if ( - startNode !== null && - (position.x < parseFloat(startNode.getAttribute("x"), 10) || - position.x > parseFloat(startNode.getAttribute("x"), 10) + nodeWidth || - position.y < parseFloat(startNode.getAttribute("y"), 10) || - position.y > parseFloat(startNode.getAttribute("y"), 10) + nodeHeight) - ) { - if (curPath === null) { - // node to elbow path - var pathString = findClosest( - { - x: parseFloat(startNode.getAttribute("x"), 10), - y: parseFloat(startNode.getAttribute("y"), 10), - }, - "node", - position, - "elbow" - ) - startPath(pathString, "path") - } else { - // elbow to elbow path - curPath.setAttributeNS( - null, - "d", - curPath.getAttribute("d") + "L" + position.x + "," + position.y + " " - ) - } - - makeElbow(position) - } - } else if (mode === "region-mode") { - var elbow - - if (startPoint === null) { - // start a region - startPoint = document.createElementNS(xmlns, "circle") - - startPoint.setAttributeNS(null, "cx", position.x) - startPoint.setAttributeNS(null, "cy", position.y) - startPoint.setAttributeNS(null, "r", 4) - startPoint.setAttributeNS(null, "class", "rElbow") // !! CHANGE CLASS - - startPoint.addEventListener("mousedown", selectElbow, false) - svgDoc.appendChild(startPoint) - - startPoint.partOfPath = "start" - } else if (curPath === null) { - // first elbow - startPath( - "M" + - startPoint.getAttribute("cx") + - "," + - startPoint.getAttribute("cy") + - " L" + - position.x + - "," + - position.y + - " ", - "region" - ) - //curPath.setAttributeNS(null, 'class', 'region'); - curPath.setAttributeNS(null, "id", "r" + regionId) - elbow = makeElbow(position) - elbow.partOfPath = "elbow" - } else { - curPath.setAttributeNS( - null, - "d", - curPath.getAttribute("d") + "L" + position.x + "," + position.y + " " - ) - elbow = makeElbow(position) - elbow.partOfPath = "elbow" - } - } -} - -/** - * Handles the clicking of the target of the event (a node) in different modes. - * In erase-mode, erases the node, and all edges in and out of the node. - * In change-mode, moves the node, and in path-mode, marks it a start node - * or creates a path if valid. // !! FIX DESCRIPTION - * @param {object} e The mousedown event. - */ -function nodeClicked(e) { - "use strict" - - var index = null - - var targetNode = null - if (e.currentTarget.id[0] === "t") { - targetNode = document.getElementById("n" + e.currentTarget.id.slice(1)) - } else { - targetNode = e.currentTarget - } - - if (mode === "erase-mode") { - // remove any paths leading to and from this node from the other node's - // list of paths and remove this node from the other nodes' adjacency lists - targetNode.inEdges.map(function (edge) { - // Remove edge from parent's outEdges and current node from parent's successors list - var edgeParent = document.getElementById( - edge.id.slice(0, edge.id.lastIndexOf("n")) - ) - index = edgeParent.outEdges.indexOf(edge) - if (index > -1) { - edgeParent.outEdges.splice(index, 1) - } - index = edgeParent.successors.indexOf(targetNode) - if (index > -1) { - edgeParent.successors.splice(index, 1) - } - erasePath(edge) - }) - targetNode.outEdges.map(function (edge) { - // Remove edge from children's inEdges and current node from child's parents list - var edgeChild = document.getElementById( - edge.id.slice(edge.id.lastIndexOf("n")) - ) - index = edgeChild.inEdges.indexOf(edge) - if (index > -1) { - edgeChild.inEdges.splice(index, 1) - } - index = edgeChild.predecessors.indexOf(targetNode) - if (index > -1) { - edgeChild.predecessors.splice(index, 1) - } - erasePath(edge) - }) - svgDoc.removeChild(targetNode.parentNode) - } else if (mode === "change-mode") { - var position = getClickPosition(e, targetNode) - - nodeMoving = targetNode - prevX = position.x - prevY = position.y - - // show which node has been selected - select(targetNode) - } else if (mode === "path-mode") { - if (startNode === null) { - startNode = targetNode - select(targetNode) - } else if (startNode === targetNode) { - // this is the start node of the path about to be created, self loops not allowed - if (curPath !== null) { - curPath.elbows.map(function (item) { - svgDoc.removeChild(item) - }) - svgDoc.removeChild(curPath) - curPath = null - } - } else { - // make the path from startNode to current node then make startNode Null - var pathId = startNode.id + targetNode.id - if (document.getElementById(pathId) === null) { - finishPath(pathId, targetNode) - startNode = null - curPath = null - } else { - // a path between these two nodes already, duplicates not allowed - startNode = null - if (curPath !== null) { - curPath.elbows.map(function (item) { - svgDoc.removeChild(item) - }) - svgDoc.removeChild(curPath) - curPath = null - } - } - } - } -} - -/** - * Selects the node newNode and unselects the old node nodeSelected. - * @param {SVGElement} newNode The node to be selected. - */ -function select(newNode) { - "use strict" - - if (nodeSelected !== null) { - nodeSelected.parentNode.setAttribute("data-active", "unselected") - } - nodeSelected = newNode - nodeSelected.parentNode.setAttribute("data-active", "active") -} - -/** - * In change-mode, moves the node or elbow that is currently being moved. - * @param {object} e The mousemove Event. - */ -export function moveNodeElbow(e) { - "use strict" - - if (mode === "change-mode") { - var position - - if (nodeMoving !== null) { - position = getClickPosition(e, nodeMoving) - var rectX = parseFloat(nodeMoving.getAttribute("x"), 10) - var rectY = parseFloat(nodeMoving.getAttribute("y"), 10) - rectX += position.x - prevX - rectY += position.y - prevY - nodeMoving.setAttribute("x", rectX) - nodeMoving.setAttribute("y", rectY) - - if (nodeMoving.parentNode.childNodes.length > 1) { - // move text - var textNode = nodeMoving.parentNode.childNodes[1] - var textX = parseFloat(textNode.getAttribute("x"), 10) - var textY = parseFloat(textNode.getAttribute("y"), 10) - textX += position.x - prevX - textY += position.y - prevY - textNode.setAttribute("x", textX) - textNode.setAttribute("y", textY) - } - - // move in and out edges by the same amount - nodeMoving.inEdges.map(function (item) { - // modify last node in path - movePath(item, position.x - prevX, position.y - prevY, "end", -1) - }) - nodeMoving.outEdges.map(function (item) { - // modify the first node in path - movePath(item, position.x - prevX, position.y - prevY, "start", -1) - }) - - prevX = position.x - prevY = position.y - } else if (elbowMoving !== null) { - position = getClickPosition(e, elbowMoving) - moveElbow(elbowMoving, position) - prevX = position.x - prevY = position.y - } else if (regionMoving !== null) { - // move each elbow - position = getClickPosition(e, regionMoving) - regionMoving.elbows.map(function (elbow) { - moveElbow(elbow, position) - }) - prevX = position.x - prevY = position.y - } - } -} - -/** - * - * @param elbow - * @param position - */ -function moveElbow(elbow, position) { - "use strict" - - // move dummy node - var elbowX = parseFloat(elbow.getAttribute("cx"), 10) - var elbowY = parseFloat(elbow.getAttribute("cy"), 10) - elbowX += position.x - prevX - elbowY += position.y - prevY - elbow.setAttribute("cx", elbowX) - elbow.setAttribute("cy", elbowY) - - // move actual elbow in path - var partOfPath = "elbow" - if (elbow.getAttribute("class") === "rElbow") { - partOfPath = elbow.partOfPath - } - - movePath( - document.getElementById(elbow.path), - position.x - prevX, - position.y - prevY, - "elbow", - document.getElementById(elbow.path).elbows.indexOf(elbow) - ) -} - -/** - * Reinitializes global variables associated with mousedown and mousemove event. - * @param {object} e The mouseup event. - */ -export function unclickAll(e) { - "use strict" - - if (mode === "change-mode") { - nodeMoving = null - prevX = -1 - prevY = -1 - elbowMoving = null - regionMoving = null - } -} - -/** - * - */ -function finishRegion() { - "use strict" - - if ( - mode === "region-mode" && - curPath !== null && - curPath.elbows.length >= 3 - ) { - curPath.setAttributeNS(null, "d", curPath.getAttribute("d") + "Z") - curPath.setAttributeNS(null, "style", "fill:#" + document.getElementById("select-colour").value) - curPath.addEventListener("mousedown", regionClicked, false) - curPath.setAttributeNS(null, "pointer-events", "boundingBox") // to solve point in polygon problem - curPath.setAttributeNS(null, "class", "region") - curPath.setAttributeNS(null, "data-active", "region") - - curPath.elbows.map(function (item) { - item.path = "r" + regionId - item.setAttributeNS(null, "class", "rElbow") - }) - - regionId += 1 - curPath = null - startPoint = null - } else if (curPath !== null && curPath.elbows.length < 3) { - curPath.elbows.map(function (item) { - svgDoc.removeChild(item) - }) - document.getElementById("regions").removeChild(curPath) - } -} - -/** - * - * @param e - */ -function regionClicked(e) { - "use strict" - if (mode === "erase-mode") { - // delete the dummy nodes and the path itself - e.currentTarget.elbows.map(function (item) { - svgDoc.removeChild(item) - }) - document.getElementById("regions").removeChild(e.currentTarget) - } else if (mode === "change-mode") { - var position = getClickPosition(e, e.currentTarget) - regionMoving = e.currentTarget - prevX = position.x - prevY = position.y - } -} - -/** - * Parse the SVG canvas and convert all the elements of the graph into a JSON list. - * Note: The graph ID is set to a "dummy" value of -1. - * @return {JSON} A JSON string which stores the parsed SVG elements. - */ -function convertSvgToJson() { - "use strict" - - var gId = -1 - var texts = [] - var shapes = [] - var paths = [] - var svgElements = document.getElementById("mySVG").children - for (var i = 0; i < svgElements.length; i++) { - if (svgElements[i].tagName === "g" && svgElements[i].id !== "regions") { - var gText = svgElements[i].querySelector("text") - if (gText !== null) { - texts.push({ - graph: gId, - rId: "", - pos: [ - parseFloat(gText.getAttribute("x")), - parseFloat(gText.getAttribute("y")), - ], - text: gText.textContent, - align: "begin", - fill: "", - }) - } - - var gRect = svgElements[i].querySelector("rect") - shapes.push({ - graph: gId, - id_: "", - pos: [ - parseFloat(gRect.getAttribute("x")), - parseFloat(gRect.getAttribute("y")), - ], - width: parseFloat(gRect.getAttribute("width")), - height: parseFloat(gRect.getAttribute("height")), - fill: "none", - stroke: "", - text: gText !== null ? texts.slice(-1) : [], - tolerance: 9, - type_: "Node", - }) - } else if (svgElements[i].tagName === "path") { - paths.push({ - graph: gId, - id_: "", - points: getPathCoords(svgElements[i].getAttribute("d")), - fill: "none", - stroke: "", - isRegion: false, - source: "", - target: "", - }) - } - } - - return JSON.stringify({ texts: texts, shapes: shapes, paths: paths }) -} - -/** - * Convert path tag coordinates into a list of tuples. - * @param {String} pathCoords The set of path coordinates within the "d" attribute of a HTML tag. - * @return {[String]} A list of tuples. - */ -function getPathCoords(pathCoords) { - "use strict" - - return pathCoords - .split(" ") - .filter(function (entry) { - return entry !== "" - }) - .map(function (coord) { - return coord.slice(1).split(",").map(parseFloat) - }) -} - -/** - * Find the closest node (to the given coordinates), and return its text value. - * @param {[Float]} coords A single set of XY-coordinates. - * @return {String} The text value of the closest node. - */ -function getClosestText(coords, nodeList) { - "use strict" - - return nodeList - .map(function (node) { - var a = node.pos[0] - coords[0] - var b = node.pos[1] - coords[1] - return [node.text[0].text, Math.sqrt(a * a + b * b)] - }) - .sort(function (a, b) { - return a[1] === b[1] ? 0 : a[1] < b[1] ? -1 : 1 - })[0][0] -} - -/* - * Convert JSON data into SVG elements then populate the canvas with them. - */ -function renderJson(jsonStr) { - "use strict" - - var jsonData = JSON.parse(jsonStr) - - // Parse Path data - jsonData.paths.forEach(function (jsonPath) { - // Create Paths and Regions - var path = document.createElementNS(xmlns, "path") - path.setAttributeNS(null, "id", "pathp" + nodeId) - path.setAttributeNS(null, "d", "M" + jsonPath.points.join(" ")) - path.setAttributeNS(null, "data-active", "inactive") - if (jsonPath.isRegion) { - path.setAttributeNS(null, "class", "region") - path.setAttributeNS(null, "style", "fill:" + jsonPath.fill) - } else { - path.setAttributeNS(null, "stroke", "black") - path.setAttributeNS(null, "marker-end", "url(#arrow)") - path.setAttributeNS(null, "class", "path") - path.setAttributeNS(null, "data-active", "drawn") - } - - svgDoc.appendChild(path) - nodeId += 1 - }) - - // generate SVG nodes - jsonData.shapes.forEach(function (jsonShape) { - makeNode(jsonShape.pos[0], jsonShape.pos[1], jsonShape) - }) - - // Parse Text data - jsonData.texts.forEach(function (jsonText) { - if (jsonText.rId.indexOf("tspan") > -1) { - var code = document.createElementNS(xmlns, "text") - code.setAttributeNS(null, "id", "tspan" + nodeId) - code.setAttributeNS(null, "fill", jsonText.fill) - code.setAttributeNS(null, "align", jsonText.align) - code.setAttributeNS(null, "x", jsonText.pos[0]) - code.setAttributeNS(null, "y", jsonText.pos[1]) - code.setAttributeNS(null, "class", "region-label") - var textNode = document.createTextNode(jsonText.text) - code.appendChild(textNode) - svgDoc.appendChild(code) - - nodeId += 1 - } - }) -} diff --git a/js/components/draw/main.js b/js/components/draw/main.js deleted file mode 100644 index 299c88a25..000000000 --- a/js/components/draw/main.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react" -import { createRoot } from 'react-dom/client' -import { Graph } from "../graph/Graph" -import { ErrorBoundary } from "react-error-boundary" -import GraphFallback from "../graph/GraphFallback" - -document.addEventListener("DOMContentLoaded", () => { - const container = document.getElementById("react-graph") - const root = createRoot(container) - root.render( - - - -) -}) diff --git a/public/js/draw/draw.js b/public/js/draw/draw.js deleted file mode 100644 index f1daaa55a..000000000 --- a/public/js/draw/draw.js +++ /dev/null @@ -1,625 +0,0 @@ - -/** - * Calculates the position of the click in relation to the page. - * @param {object} e The click event. - * @param {HTMLElement} elem The target of the click event. - * @return {object} The position of the click. - */ -function getClickPosition(e, elem) { - 'use strict'; - - var parentPosition = getPosition(elem); - var xPosition = e.clientX - parentPosition.x; - var yPosition = e.clientY - parentPosition.y; - xPosition = Math.round(xPosition / 4) * 4; // for snapping!! - yPosition = Math.round(yPosition / 4) * 4; - - return { x: xPosition, y: yPosition }; -} - - -/** - * Calculates the position of elem in relation to the page. - * @param {HTMLElement} elem The target of the click event. - * @return {object} The position of elem on the page. - */ -function getPosition(elem) { - 'use strict'; - - var xPosition = 0; - var yPosition = 0; - - while (elem) { - // || 0 for firefox compatability - xPosition += (elem.offsetLeft || 0) - elem.scrollLeft + elem.clientLeft; - yPosition += (elem.offsetTop || 0) - elem.scrollTop + elem.clientTop; - elem = elem.parentElement; // offsetParent undefined in mozilla - } - return { x: xPosition, y: yPosition }; -} - -/** - * Creates a new node within the SVG canvas with specific attributes. - * If no attributes are specified, then a generic blank node is created. - * @param {String} posX The x-coordinate of the node. - * @param {String} posY The y-coordinate of the node. - * @param {JSON} jsonObj Specifies the node's attributes. - */ -function makeNode(posX, posY, jsonObj) { - 'use strict'; - - var textPosX = posX; - var textPosY = posY; - var textStr = ''; - var textFill = ''; - var textAlign = 'begin'; - var textId = 't' + nodeId; - - if (jsonObj) { - var nodeWidth = jsonObj.width; - var nodeHeight = jsonObj.height; - var nodeFill = jsonObj.fill || 'none'; - var nodeId_ = 'n' + jsonObj.id_; - var nodeTolerance = jsonObj.tolerance; - - switch (jsonObj.type_) { - case 'Hybrid': - var node = document.createElementNS(xmlns, 'rect'); - var gClass = 'hybrid'; - textFill = 'white'; - break; - case 'BoolNode': - var node = document.createElementNS(xmlns, 'ellipse'); - var gClass = 'bool'; - node.setAttribute('stroke', 'black'); - node.setAttribute('rx', 10); - node.setAttribute('ry', 7); - node.setAttribute('cx', posX); - node.setAttribute('cy', posY); - break; - default: // Node - var node = document.createElementNS(xmlns, 'rect'); - var gClass = 'node'; - node.setAttribute('rx', 4); - node.setAttribute('ry', 4); - } - - } else { - var nodeWidth = 40; - var nodeHeight = 32; - var nodeFill = '#' + document.getElementById('select-colour').value; - var nodeId_ = 'n' + nodeId; - var nodeTolerance = 9; - - var gClass = 'node'; - var node = document.createElementNS(xmlns, 'rect'); - node.setAttribute('rx', 4); - node.setAttribute('ry', 4); - } - - var g = document.createElementNS(xmlns, 'g'); - - g.setAttribute('class', gClass); - g.setAttribute('id', 'g' + nodeId); - g.setAttribute('data-active', 'active'); - - node.setAttribute('x', posX); - node.setAttribute('y', posY); - node.setAttribute('fill', nodeFill); - node.setAttribute('id', nodeId_); - node.setAttribute('width', nodeWidth); - node.setAttribute('height', nodeHeight); - node.setAttribute('class', 'node'); - node.setAttribute('tolerance', nodeTolerance); - node.predecessors = []; - node.successors = []; - // note: children doesn't work because javascript objects already have a children attribute - node.inEdges = []; - node.outEdges = []; - - g.appendChild(node); - document.getElementById('nodes').appendChild(g); - document.getElementById(nodeId_).addEventListener('mousedown', nodeClicked, false); - - // Input Text into Shape - if (jsonObj) { - for (var i = 0; i < jsonObj.text.length; i++) { - textPosX = jsonObj.pos[0]; - if (jsonObj.type_ !== 'BoolNode') { - textPosX += (jsonObj.width/2) - } - - textPosY = jsonObj.text[i].pos[1] - (jsonObj.height/4); - textStr = jsonObj.text[i].text || ''; - textFill = jsonObj.text[i].fill; - textAlign = jsonObj.text[i].align; - textId = 't' + jsonObj.id_; - - var code = document.createElementNS(xmlns, 'text'); - code.setAttributeNS(null, 'id', textId); - code.setAttributeNS(null, 'fill', textFill); - code.setAttributeNS(null, 'align', textAlign); - code.setAttributeNS(null, 'x', textPosX); - code.setAttributeNS(null, 'y', textPosY); - code.setAttributeNS(null, 'class', 'mylabel'); // note: label is a class in bootstrap - var textNode = document.createTextNode(textStr); - code.appendChild(textNode); - g.appendChild(code); - document.getElementById(textId).addEventListener('mousedown', nodeClicked, false); - }; - } - select(document.getElementById(nodeId_)); - nodeId += 1; -} - -/** - * In node-mode creates a new node at the position of the click event on the SVG canvas. - * In path-mode creates an elbow at the position of the click event on the SVG canvas, - if the startNode is defined. - * @param {object} e The mousedown event. - */ -export function makeNodePath(e) { - 'use strict'; - var position = getClickPosition(e, e.currentTarget); - if (mode === 'node-mode') { - makeNode(position.x, position.y); - } else if (mode === 'path-mode') { - // make elbow joint, only if the dummy point is outside the starting node - if (startNode !== null && ((position.x < parseFloat(startNode.getAttribute('x'), 10)) || - (position.x > parseFloat(startNode.getAttribute('x'), 10) + nodeWidth) || - (position.y < parseFloat(startNode.getAttribute('y'), 10)) || - (position.y > parseFloat(startNode.getAttribute('y'), 10) + nodeHeight))) { - if (curPath === null) { // node to elbow path - var pathString = findClosest({x: parseFloat(startNode.getAttribute('x'), 10), - y: parseFloat(startNode.getAttribute('y'), 10)}, - 'node', position, 'elbow'); - startPath(pathString, 'path'); - } else { // elbow to elbow path - curPath.setAttributeNS(null, 'd', curPath.getAttribute('d') + 'L' + position.x + ',' + position.y + ' '); - } - - makeElbow(position); - } - } else if (mode === 'region-mode') { - var elbow; - - if (startPoint === null) { // start a region - startPoint = document.createElementNS(xmlns, 'circle'); - - startPoint.setAttributeNS(null, 'cx', position.x); - startPoint.setAttributeNS(null, 'cy', position.y); - startPoint.setAttributeNS(null, 'r', 4); - startPoint.setAttributeNS(null, 'class', 'rElbow'); // !! CHANGE CLASS - - startPoint.addEventListener('mousedown', selectElbow, false); - svgDoc.appendChild(startPoint); - - startPoint.partOfPath = 'start'; - - } else if (curPath === null) { // first elbow - startPath('M' + startPoint.getAttribute('cx') + ',' + startPoint.getAttribute('cy') + ' L' + position.x + ',' + position.y + ' ', 'region'); - //curPath.setAttributeNS(null, 'class', 'region'); - curPath.setAttributeNS(null, 'id', 'r' + regionId); - elbow = makeElbow(position); - elbow.partOfPath = 'elbow'; - } else { - curPath.setAttributeNS(null, 'd', curPath.getAttribute('d') + 'L' + position.x + ',' + position.y + ' '); - elbow = makeElbow(position); - elbow.partOfPath = 'elbow'; - } - } -} - - -/** - * Handles the clicking of the target of the event (a node) in different modes. - * In erase-mode, erases the node, and all edges in and out of the node. - * In change-mode, moves the node, and in path-mode, marks it a start node - * or creates a path if valid. // !! FIX DESCRIPTION - * @param {object} e The mousedown event. - */ -function nodeClicked(e) { - 'use strict'; - - var index = null; - - var targetNode = null; - if (e.currentTarget.id[0] === 't') { - targetNode = document.getElementById('n' + e.currentTarget.id.slice(1)); - } else { - targetNode = e.currentTarget; - } - - if (mode === 'erase-mode') { - // remove any paths leading to and from this node from the other node's - // list of paths and remove this node from the other nodes' adjacency lists - targetNode.inEdges.map(function (edge) { - // Remove edge from parent's outEdges and current node from parent's successors list - var edgeParent = document.getElementById(edge.id.slice(0, edge.id.lastIndexOf('n'))); - index = edgeParent.outEdges.indexOf(edge); - if (index > -1) { - edgeParent.outEdges.splice(index, 1); - } - index = edgeParent.successors.indexOf(targetNode); - if (index > -1) { - edgeParent.successors.splice(index, 1); - } - erasePath(edge); - }); - targetNode.outEdges.map(function (edge) { - // Remove edge from children's inEdges and current node from child's parents list - var edgeChild = document.getElementById(edge.id.slice(edge.id.lastIndexOf('n'))); - index = edgeChild.inEdges.indexOf(edge); - if (index > -1) { - edgeChild.inEdges.splice(index, 1); - } - index = edgeChild.predecessors.indexOf(targetNode); - if (index > -1) { - edgeChild.predecessors.splice(index, 1); - } - erasePath(edge); - }); - svgDoc.removeChild(targetNode.parentNode); - } else if (mode === 'change-mode') { - var position = getClickPosition(e, targetNode); - - nodeMoving = targetNode; - prevX = position.x; - prevY = position.y; - - // show which node has been selected - select(targetNode); - - } else if (mode === 'path-mode') { - if (startNode === null) { - startNode = targetNode; - select(targetNode); - } else if (startNode === targetNode) { - // this is the start node of the path about to be created, self loops not allowed - if (curPath !== null) { - curPath.elbows.map(function (item) { - svgDoc.removeChild(item); - }); - svgDoc.removeChild(curPath); - curPath = null; - } - } else { - // make the path from startNode to current node then make startNode Null - var pathId = startNode.id + targetNode.id; - if (document.getElementById(pathId) === null) { - finishPath(pathId, targetNode); - startNode = null; - curPath = null; - } else { - // a path between these two nodes already, duplicates not allowed - startNode = null; - if (curPath !== null) { - curPath.elbows.map(function (item) { - svgDoc.removeChild(item); - }); - svgDoc.removeChild(curPath); - curPath = null; - } - } - } - } -} - - -/** - * Selects the node newNode and unselects the old node nodeSelected. - * @param {SVGElement} newNode The node to be selected. - */ -function select(newNode) { - 'use strict'; - - if (nodeSelected !== null) { - nodeSelected.parentNode.setAttribute('data-active', 'unselected'); - } - nodeSelected = newNode; - nodeSelected.parentNode.setAttribute('data-active', 'active'); -} - - -/** - * In change-mode, moves the node or elbow that is currently being moved. - * @param {object} e The mousemove Event. - */ -export function moveNodeElbow(e) { - 'use strict'; - - if (mode === 'change-mode') { - var position; - - if (nodeMoving !== null) { - position = getClickPosition(e, nodeMoving); - var rectX = parseFloat(nodeMoving.getAttribute('x'), 10); - var rectY = parseFloat(nodeMoving.getAttribute('y'), 10); - rectX += (position.x - prevX); - rectY += (position.y - prevY); - nodeMoving.setAttribute('x', rectX); - nodeMoving.setAttribute('y', rectY); - - if (nodeMoving.parentNode.childNodes.length > 1) { - // move text - var textNode = nodeMoving.parentNode.childNodes[1]; - var textX = parseFloat(textNode.getAttribute('x'), 10); - var textY = parseFloat(textNode.getAttribute('y'), 10); - textX += (position.x - prevX); - textY += (position.y - prevY); - textNode.setAttribute('x', textX); - textNode.setAttribute('y', textY); - } - - // move in and out edges by the same amount - nodeMoving.inEdges.map(function (item) { // modify last node in path - movePath(item, (position.x - prevX), (position.y - prevY), 'end', -1); - }); - nodeMoving.outEdges.map(function (item) { // modify the first node in path - movePath(item, (position.x - prevX), (position.y - prevY), 'start', -1); - }); - - prevX = position.x; - prevY = position.y; - } else if (elbowMoving !== null) { - position = getClickPosition(e, elbowMoving); - moveElbow(elbowMoving, position); - prevX = position.x; - prevY = position.y; - } else if (regionMoving !== null) { - // move each elbow - position = getClickPosition(e, regionMoving); - regionMoving.elbows.map(function (elbow) { - moveElbow(elbow, position); - }); - prevX = position.x; - prevY = position.y; - } - } -} - - -/** - * - * @param elbow - * @param position - */ -function moveElbow(elbow, position) { - 'use strict'; - - // move dummy node - var elbowX = parseFloat(elbow.getAttribute('cx'), 10); - var elbowY = parseFloat(elbow.getAttribute('cy'), 10); - elbowX += (position.x - prevX); - elbowY += (position.y - prevY); - elbow.setAttribute('cx', elbowX); - elbow.setAttribute('cy', elbowY); - - // move actual elbow in path - var partOfPath = 'elbow'; - if (elbow.getAttribute('class') === 'rElbow') { - partOfPath = elbow.partOfPath; - } - - movePath(document.getElementById(elbow.path), - (position.x - prevX), (position.y - prevY), 'elbow', - document.getElementById(elbow.path).elbows.indexOf(elbow)); -} - - -/** - * Reinitializes global variables associated with mousedown and mousemove event. - * @param {object} e The mouseup event. - */ -export function unclickAll(e) { - 'use strict'; - - if (mode === 'change-mode') { - nodeMoving = null; - prevX = -1; - prevY = -1; - elbowMoving = null; - regionMoving = null; - } -} - - -/** - * - */ -function finishRegion() { - 'use strict'; - - if (mode === 'region-mode' && curPath !== null && curPath.elbows.length >= 3) { - curPath.setAttributeNS(null, 'd', curPath.getAttribute('d') + 'Z'); - curPath.setAttributeNS(null, 'style', 'fill:#' + document.getElementById('select-colour').value); - curPath.addEventListener('mousedown', regionClicked, false); - curPath.setAttributeNS(null, 'pointer-events','boundingBox'); // to solve point in polygon problem - curPath.setAttributeNS(null, 'class', 'region'); - curPath.setAttributeNS(null, 'data-active', 'region'); - - curPath.elbows.map(function (item) { - item.path = 'r' + regionId; - item.setAttributeNS(null, 'class', 'rElbow'); - }); - - regionId += 1; - curPath = null; - startPoint = null; - } else if (curPath !== null && curPath.elbows.length < 3) { - curPath.elbows.map(function (item) { - svgDoc.removeChild(item); - }); - document.getElementById('regions').removeChild(curPath); - } -} - - -/** - * - * @param e - */ -function regionClicked(e) { - 'use strict'; - if (mode === 'erase-mode') { - // delete the dummy nodes and the path itself - e.currentTarget.elbows.map(function (item) { - svgDoc.removeChild(item); - }); - document.getElementById('regions').removeChild(e.currentTarget); - } else if (mode === 'change-mode') { - var position = getClickPosition(e, e.currentTarget); - regionMoving = e.currentTarget; - prevX = position.x; - prevY = position.y; - } -} - - -/** - * Parse the SVG canvas and convert all the elements of the graph into a JSON list. - * Note: The graph ID is set to a "dummy" value of -1. - * @return {JSON} A JSON string which stores the parsed SVG elements. - */ -function convertSvgToJson() { - 'use strict'; - - var gId = -1; - var texts = []; - var shapes = []; - var paths = []; - var svgElements = document.getElementById('mySVG').children; - for (var i = 0; i < svgElements.length; i++) { - if (svgElements[i].tagName === 'g' && svgElements[i].id !== 'regions') { - var gText = svgElements[i].querySelector('text'); - if (gText !== null) { - texts.push({ - 'graph' : gId, - 'rId' : '', - 'pos' : [ parseFloat(gText.getAttribute('x')), - parseFloat(gText.getAttribute('y')) - ], - 'text' : gText.textContent, - 'align' : 'begin', - 'fill' : '' - }); - } - - var gRect = svgElements[i].querySelector('rect'); - shapes.push({ - 'graph' : gId, - 'id_' : '', - 'pos' : [ parseFloat(gRect.getAttribute('x')), - parseFloat(gRect.getAttribute('y')) - ], - 'width' : parseFloat(gRect.getAttribute('width')), - 'height' : parseFloat(gRect.getAttribute('height')), - 'fill' : 'none', - 'stroke' : '', - 'text' : ((gText !== null) ? texts.slice(-1) : []), - 'tolerance' : 9, - 'type_' : 'Node' - }); - } else if (svgElements[i].tagName === 'path') { - paths.push({ - 'graph' : gId, - 'id_' : '', - 'points' : getPathCoords(svgElements[i].getAttribute('d')), - 'fill' : 'none', - 'stroke' : '', - 'isRegion' : false, - 'source' : '', - 'target' : '' - }); - } - } - - return JSON.stringify({texts:texts, shapes:shapes, paths:paths}); -} - - -/** - * Convert path tag coordinates into a list of tuples. - * @param {String} pathCoords The set of path coordinates within the "d" attribute of a HTML tag. - * @return {[String]} A list of tuples. - */ -function getPathCoords(pathCoords) { - 'use strict'; - - return pathCoords.split(' ').filter(function(entry) { - return (entry !== '') - }).map(function(coord) { - return coord.slice(1).split(',').map(parseFloat); - }); -} - - -/** - * Find the closest node (to the given coordinates), and return its text value. - * @param {[Float]} coords A single set of XY-coordinates. - * @return {String} The text value of the closest node. - */ -function getClosestText(coords, nodeList) { - 'use strict'; - - return nodeList.map(function(node) { - var a = node.pos[0] - coords[0]; - var b = node.pos[1] - coords[1]; - return [node.text[0].text, Math.sqrt( a*a + b*b )]; - }).sort(function(a,b) { - return a[1] === b[1] ? 0 : a[1] < b[1] ? -1: 1 - })[0][0]; -} - -/* - * Convert JSON data into SVG elements then populate the canvas with them. - */ -function renderJson(jsonStr) { - 'use strict'; - - var jsonData = JSON.parse(jsonStr); - - // Parse Path data - jsonData.paths.forEach(function(jsonPath) { - // Create Paths and Regions - var path = document.createElementNS(xmlns, 'path'); - path.setAttributeNS(null, 'id', 'pathp' + nodeId); - path.setAttributeNS(null, 'd', 'M' + jsonPath.points.join(' ')); - path.setAttributeNS(null, 'data-active', 'inactive'); - if (jsonPath.isRegion) { - path.setAttributeNS(null, 'class', 'region'); - path.setAttributeNS(null, 'style', 'fill:' + jsonPath.fill); - } else { - path.setAttributeNS(null, 'stroke', 'black'); - path.setAttributeNS(null, 'marker-end', 'url(#arrow)'); - path.setAttributeNS(null, 'class', 'path'); - path.setAttributeNS(null, 'data-active', 'drawn'); - } - - svgDoc.appendChild(path); - nodeId += 1; - }); - - // generate SVG nodes - jsonData.shapes.forEach(function(jsonShape) { - makeNode(jsonShape.pos[0], jsonShape.pos[1], jsonShape); - }); - - // Parse Text data - jsonData.texts.forEach(function(jsonText) { - if (jsonText.rId.indexOf('tspan') > -1) { - var code = document.createElementNS(xmlns, 'text'); - code.setAttributeNS(null, 'id', 'tspan' + nodeId); - code.setAttributeNS(null, 'fill', jsonText.fill); - code.setAttributeNS(null, 'align', jsonText.align); - code.setAttributeNS(null, 'x', jsonText.pos[0]); - code.setAttributeNS(null, 'y', jsonText.pos[1]); - code.setAttributeNS(null, 'class', 'region-label'); - var textNode = document.createTextNode(jsonText.text); - code.appendChild(textNode); - svgDoc.appendChild(code); - - nodeId += 1; - } - }); -} diff --git a/public/js/draw/path.js b/public/js/draw/path.js deleted file mode 100644 index ea19045ef..000000000 --- a/public/js/draw/path.js +++ /dev/null @@ -1,317 +0,0 @@ -/* CREATE PATHS */ - -/** - * Make the dummy elbow node with center at position position. - * @position {object} position The x and y position of the dummy node being created. - * @returns - */ -function makeElbow(position) { - 'use strict'; - - var elbow = document.createElementNS(xmlns, 'circle'); - - elbow.setAttributeNS(null, 'cx', position.x); - elbow.setAttributeNS(null, 'cy', position.y); - elbow.setAttributeNS(null, 'r', 4); - elbow.setAttributeNS(null, 'class', 'elbow'); - - elbow.addEventListener('mousedown', selectElbow, false); - svgDoc.appendChild(elbow); - - curPath.elbows.push(elbow); - - return elbow; -} - - -/** - * Creates an SVG path that has the coordinates specified by pathString. - * @param {string} pathString The coordinates of the new path to be created. - * @param {string} type The type of the path (could also be a region). - */ -function startPath(pathString, type) { - 'use strict'; - - // note: id will get set when the path is complete, also marker (arrowhead) - // curPath will get modified until path is complete - curPath = document.createElementNS(xmlns, 'path'); - curPath.setAttributeNS(null, 'd', pathString); - curPath.setAttributeNS(null, 'stroke', 'black'); - curPath.setAttributeNS(null, 'class', 'path'); - curPath.elbows = []; - if (type === 'path') { - curPath.setAttributeNS(null, 'data-active', 'drawn'); - svgDoc.appendChild(curPath); - } else { - curPath.elbows.push(startPoint); - document.getElementById('regions').appendChild(curPath); - } -} - - -/** - * Creates a new path or completes curPath by ending it at endNode and giving it - * the id pathID. - * @param{string} pathId The id of the now complete path. - * @param{SVGElement} endNode The last coordinate for the path. - */ -function finishPath(pathId, endNode) { - 'use strict'; - - var pathString; - - if (curPath === null) { // create a new path, node to node - pathString = findClosest( {x: parseFloat(startNode.getAttribute('x'), 10), - y: parseFloat(startNode.getAttribute('y'), 10)}, - 'node', - {x: parseFloat(endNode.getAttribute('x'), 10), - y: parseFloat(endNode.getAttribute('y'), 10)}, - 'node'); - - startPath(pathString, 'path'); - } else { // finish curPath, elbow to node - var curElbow = {x: parseFloat(curPath.elbows[curPath.elbows.length - 1].getAttribute('cx'), 10), - y: parseFloat(curPath.elbows[curPath.elbows.length - 1].getAttribute('cy'), 10)}; - pathString = findClosest(curElbow, 'elbow', - {x: parseFloat(endNode.getAttribute('x'), 10), - y: parseFloat(endNode.getAttribute('y'), 10)}, - 'node'); - curPath.setAttributeNS(null, 'd', curPath.getAttribute('d') + pathString); - } - - select(endNode); - curPath.elbows.map(function (item) { - item.path = pathId; - }); - curPath.setAttributeNS(null, 'id', pathId); - curPath.setAttributeNS(null, 'class', 'path'); - curPath.setAttributeNS(null, 'marker-end', 'url(#arrow)'); - curPath.addEventListener('click', pathClicked, false); - - // update relationships - startNode.kids.push(endNode); - endNode.parents.push(startNode); - startNode.outEdges.push(curPath); - endNode.inEdges.push(curPath); -} - - -/** - * Return the best coordinates for the start and end of a path. - * Pre-Requisites: At least one of source and target must be a node. - * @param {SVGElement} source A node or an elbow element. - * @param {string} sourceType The type of source, elbow or node. - * @param {SVGElement} target A node or an elbow element. - * @param {string} targetType The type of target, elbow or node. - */ -function findClosest(source, sourceType, target, targetType) { - 'use strict'; - - var thePath = null; - var node1Edges; - var node2Edges; - - if (sourceType === 'node' && targetType === 'elbow') { - node1Edges = [{x: source.x + nodeWidth/2, y: source.y}, - {x: source.x + nodeWidth/2, y: source.y + nodeHeight}, - {x: source.x + nodeWidth, y: source.y + nodeHeight/2}, - {x: source.x, y: source.y + nodeHeight/2}]; - node2Edges = [target]; - } else if (sourceType === 'elbow' && targetType === 'node') { - node1Edges = [source]; - node2Edges = [{x: target.x + nodeWidth/2, y: target.y}, - {x: target.x + nodeWidth/2, y: target.y + nodeHeight}, - {x: target.x + nodeWidth, y: target.y + nodeHeight/2}, - {x: target.x, y: target.y + nodeHeight/2}]; - } else { - // top, bottom, left, right - node1Edges = [{x: source.x + nodeWidth/2, y: source.y}, - {x: source.x + nodeWidth/2, y: source.y + nodeHeight}, - {x: source.x + nodeWidth, y: source.y + nodeHeight/2}, - {x: source.x, y: source.y + nodeHeight/2}]; - node2Edges = [{x: target.x + nodeWidth/2, y: target.y}, - {x: target.x + nodeWidth/2, y: target.y + nodeHeight}, - {x: target.x + nodeWidth, y: target.y + nodeHeight/2}, - {x: target.x, y: target.y + nodeHeight/2}]; - } - - // find best alignment - var best_edges = [node1Edges[0], node2Edges[0]]; - var best_dist = dist(node1Edges[0], node2Edges[0]); - for (var i = 0; i < node1Edges.length; i++) { - for (var j = 0; j < node2Edges.length; j++) { - if (dist(node1Edges[i], node2Edges[j]) < best_dist) { - best_edges = [node1Edges[i], node2Edges[j]]; - best_dist = dist(node1Edges[i], node2Edges[j]); - } - } - } - - if (sourceType === 'elbow' && targetType === 'node') { - // only need to add end point to curPath - thePath = 'L' + best_edges[1].x + ',' + best_edges[1].y + ' '; - } else { - thePath = 'M' + best_edges[0].x + ',' + best_edges[0].y + ' L' + - best_edges[1].x + ',' + best_edges[1].y + ' '; - } - - return thePath; -} - -/** - * Returns the distance between point a and point b. - * @param {object} a The coordinates of point a. - * @param {object} b The coordinates of point b. - * @return {number} The distance between a and b. - */ -function dist(a, b) { - 'use strict'; - - return Math.sqrt(((b.x - a.x) * (b.x - a.x)) + ((b.y - a.y) * (b.y - a.y))); -} - - -/* MODIFY PATHS */ -/** - * In change mode, moves target of event e (the elbow) . In erase-mode, erases elbow. - * @param {object} e The mousedown event. - */ -function selectElbow(e) { - 'use strict'; - - if (mode === 'change-mode') { - var position = getClickPosition(e, e.currentTarget); - elbowMoving = e.currentTarget; - prevX = position.x; - prevY = position.y; - } else if (mode === 'erase-mode') { - var indexOfElbow = 0; - var indexOfNext; - var thePath = document.getElementById(e.currentTarget.path); - var thePathString = thePath.getAttribute('d'); - var elbowNum = thePath.elbows.indexOf(e.currentTarget); - - if (thePath.getAttribute('class') === 'region' && thePath.elbows.length <= 3) { - // remove the whole region, can't have only 2 points in shape - thePath.elbows.map(function (item) { - svgDoc.removeChild(item); - }); - document.getElementById('regions').removeChild(thePath); - } else { - if (thePath.getAttribute('class') === 'region') { - elbowNum -= 1; - } - - // look for elbowNum-th occurance of L - for (var i = 0; i <= elbowNum; i++) { - indexOfElbow = thePathString.indexOf('L', indexOfElbow + 1); - } - indexOfNext = thePathString.indexOf('L', indexOfElbow + 1); - thePathString = thePathString.slice(0, indexOfElbow) + thePathString.slice(indexOfNext); - if (thePathString[0] !== 'M') { - // for the case when the first elbow of a region - thePathString = 'M' + thePathString.slice(1); - } - thePath.elbows.splice(thePath.elbows.indexOf(e.currentTarget), 1); - thePath.setAttributeNS(null, 'd', thePathString); - svgDoc.removeChild(e.currentTarget); - } - } -} - - -/** - * Move the partOfPath of the path by xBy and yBy units. // !! FIX DESCRIPTION - * @param {SVGElement} path The path being modified. - * @param {number} xBy The amount of movement in the x direction. - * @param {number} yBy The amount of movement in the y direction. - * @param {string} partOfPath The part of the path (start, end or elbow) path being moved. - * @param {number} elbowNum The number of the elbow being moved if partOfPath is elbow. - */ -function movePath(path, xBy, yBy, partOfPath, elbowNum) { - 'use strict'; - - var thePath = path.getAttribute('d'); - var theX = null; - var theY = null; - if (partOfPath === 'start') { - theX = parseFloat(thePath.slice(1, thePath.indexOf(',')), 10) + xBy; // exclude the M - theY = parseFloat(thePath.slice(thePath.indexOf(',') + 1, - thePath.indexOf('L')), 10) + yBy; - thePath = 'M' + theX + ',' + theY + thePath.slice(thePath.indexOf('L')); - } else if (partOfPath === 'end') { - theX = parseFloat(thePath.slice(thePath.lastIndexOf('L') + 1, - thePath.lastIndexOf(',')), 10) + xBy; - theY = parseFloat(thePath.slice(thePath.lastIndexOf(',') + 1), 10) + yBy; - thePath = thePath.slice(0, thePath.lastIndexOf('L') + 1) + theX + ',' + theY; - } else if (partOfPath === 'elbow') { - var indexOfElbow = 0; // !! elbowNum is not valid - if (thePath[thePath.length-1] === 'Z') { - elbowNum -= 1; // first elbow starts with M not L - } - var indexOfNext; - // look for elbowNum-th occurance of L - for (var i = 0; i <= elbowNum; i++) { - indexOfElbow = thePath.indexOf('L', indexOfElbow + 1); - } - indexOfNext = thePath.indexOf('L', indexOfElbow + 1); - theX = parseFloat(thePath.slice(indexOfElbow + 1, indexOfNext), 10) + xBy; - theY = parseFloat(thePath.slice(thePath.indexOf(',' , indexOfElbow) + 1, - indexOfNext), 10) + yBy; - thePath = thePath.slice(0, indexOfElbow + 1) + theX + ',' + theY + thePath.slice(indexOfNext - 1); - } - - path.setAttribute('d', thePath); -} - - -/** - * In erase mode, delete the target of event e (a path). - * @param {object} e The mousedown event. - */ -function pathClicked(e) { - 'use strict'; - - if (mode === 'erase-mode') { - erasePath(e.currentTarget); - } - -} - - -/** - * Delete the path path. - * @param {SVGElement} path - */ -function erasePath(path) { - var index = -1; - var pathId = path.id; - var beg = document.getElementById(pathId.slice(0, pathId.lastIndexOf('n'))); - var end = document.getElementById(pathId.slice(pathId.lastIndexOf('n'))); - - // delete the nodes from each others' list - index = beg.kids.indexOf(end); - if (index > -1) { - beg.kids.splice(index, 1); - } - index = end.parents.indexOf(beg); - if (index > -1) { - end.parents.splice(index, 1); - } - - // delete this path from the nodes' list - index = beg.outEdges.indexOf(path); - if (index > -1) { - beg.outEdges.splice(index, 1); - } - index = end.inEdges.indexOf(path); - if (index > -1) { - end.inEdges.splice(index, 1); - } - - // delete the dummy nodes and the path itself - path.elbows.map(function (item) { - svgDoc.removeChild(item); - }); - svgDoc.removeChild(path); -} diff --git a/public/js/draw/setup.js b/public/js/draw/setup.js deleted file mode 100644 index ecd795e2a..000000000 --- a/public/js/draw/setup.js +++ /dev/null @@ -1,141 +0,0 @@ -/* SET UP SIDEBAR AND ONCLICKS FOR BUTTONS */ - -for (const node of document.getElementsByClassName('mode')) { - node.addEventListener('click', () => changeMode(node.id)) -} - -document.getElementById('add-text').addEventListener('click', addText) -document.getElementById('finish-region').addEventListener('click', finishRegion) - -$('#colour-table').on('click', 'td', function() { - document.getElementById('select-colour').jscolor.fromString($(this).css('backgroundColor')); -}); - -document.getElementById('save-graph').addEventListener('click', () => { - $.ajax({ - url: '/save-json', - data: {'jsonData' : convertSvgToJson(), - 'nameData' : document.getElementById('area-of-study').value}, - method: 'POST', - success: function(status) { - console.log(status); - }, - error: function(xhr, status, err) { - console.error('save-graph:', status, err.toString()); - } - }); -}); - -document.getElementById('submit-graph-name').addEventListener('click', () => { - $.ajax({ - url: '/get-json-data', - data: {graphName : document.getElementById('area-of-study').value}, - dataType: 'json', - success: function(data) { - var div = document.getElementById('main'); - document.body.removeChild(div); - setupSVGCanvas(); - svgDoc.appendChild(setupMarker()); - renderJson(JSON.stringify(data)); - }, - error: function(xhr, status, err) { - console.error('graphs', status, err.toString()); - } - }); -}); - -document.addEventListener('keydown', keyboard, false); - - -/** - * Handles keydown event e, possibly switching modes. - * @param {object} e The keydown event. - */ -function keyboard(e) { - 'use strict'; - - if (document.getElementById("course-code") == document.activeElement) { - if (e.which === 78) { - changeMode("node-mode"); // n - } else if (e.which === 80) { - changeMode("path-mode"); // p - } else if (e.which === 77){ - changeMode("change-mode"); // m - } else if (e.which === 69){ - changeMode("erase-mode"); // e - } else if (e.which === 82){ - changeMode("region-mode"); // r - } else if (e.which === 70){ - finishRegion(); // f - } - } -} - - -/** - * Changes the current mode mode to the new mode with id id. - * @param {object} id The id of the new mode to be selected. - */ -function changeMode(id) { - 'use strict'; - - document.getElementById(mode).classList.toggle('clicked'); - - if (mode === 'path-mode') { - // clean up partial temp path - if (curPath !== null) { - startNode = null; - curPath.elbows.map(function (item) { - svgDoc.removeChild(item); - }); - svgDoc.removeChild(curPath); - curPath = null; - - } - } else if (mode === 'region-mode') { - //svgDoc.removeChild(startPoint); - if (curPath !== null) { - curPath.elbows.map(function (item) { - svgDoc.removeChild(item); - }); - document.getElementById('regions').removeChild(curPath); - curPath = null; - startPoint = null; - } else if (startPoint !== null) { - svgDoc.removeChild(startPoint); - startPoint = null; - } - - } - - mode = id; - document.getElementById(mode).classList.toggle('clicked'); -} - - -/** - * Adds the text from the input box to the currently selected node. - */ -function addText() { - 'use strict'; - - var courseCode = document.getElementById('course-code').value; - if (nodeSelected !== null && courseCode.length > 2) { - var g = nodeSelected.parentNode; - if (g.childNodes.length > 1) { - g.removeChild(g.childNodes[1]); - } - var code = document.createElementNS(xmlns, 'text'); - code.setAttributeNS(null, 'id', 't' + nodeSelected.id.slice(1)); - code.setAttributeNS(null, 'x', parseFloat(nodeSelected.getAttribute('x'), 10) + - nodeWidth/2); - code.setAttributeNS(null, 'y', parseFloat(nodeSelected.getAttribute('y'), 10) + - nodeHeight/2); - code.setAttributeNS(null, 'class', 'mylabel'); // note: label is a class in bootstrap - var textNode = document.createTextNode(courseCode); - code.appendChild(textNode); - g.appendChild(code); - - document.getElementById('t' + nodeSelected.id.slice(1)).addEventListener('mousedown', nodeClicked, false); - } -} diff --git a/public/js/draw/variables.js b/public/js/draw/variables.js deleted file mode 100644 index 09ba603c8..000000000 --- a/public/js/draw/variables.js +++ /dev/null @@ -1,17 +0,0 @@ -/* GLOBAL VARIABLES */ -var nodeWidth = 40; -var nodeHeight = 32; -var xmlns = 'http://www.w3.org/2000/svg'; -var svgDoc = null; -var nodeId = 0; -var mode = 'node-mode'; -var nodeMoving = null; // for movement and path creation -var prevX = -1; // for movement -var prevY = -1; // for movement -var nodeSelected = null; // for adding text or changing colour -var startNode = null; // for making paths -var curPath = null; // the path currently being created -var elbowMoving = null; // for movement of elbow joints -var regionId = 0; -var startPoint = null; -var regionMoving = null; diff --git a/public/js/vendor/jscolor.min.js b/public/js/vendor/jscolor.min.js deleted file mode 100644 index 2a7a788be..000000000 --- a/public/js/vendor/jscolor.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * jscolor - JavaScript Color Picker - * - * @link http://jscolor.com - * @license For open source use: GPLv3 - * For commercial use: JSColor Commercial License - * @author Jan Odvarko - * - * See usage examples at http://jscolor.com/examples/ - */"use strict";window.jscolor||(window.jscolor=function(){var e={register:function(){e.attachDOMReadyEvent(e.init),e.attachEvent(document,"mousedown",e.onDocumentMouseDown),e.attachEvent(document,"touchstart",e.onDocumentTouchStart),e.attachEvent(window,"resize",e.onWindowResize)},init:function(){e.jscolor.lookupClass&&e.jscolor.installByClassName(e.jscolor.lookupClass)},tryInstallOnElements:function(t,n){var r=new RegExp("(^|\\s)("+n+")(\\s*(\\{[^}]*\\})|\\s|$)","i");for(var i=0;is[u]?-r[u]+n[u]+i[u]/2>s[u]/2&&n[u]+i[u]-o[u]>=0?n[u]+i[u]-o[u]:n[u]:n[u],-r[a]+n[a]+i[a]+o[a]-l+l*f>s[a]?-r[a]+n[a]+i[a]/2>s[a]/2&&n[a]+i[a]-l-l*f>=0?n[a]+i[a]-l-l*f:n[a]+i[a]-l+l*f:n[a]+i[a]-l+l*f>=0?n[a]+i[a]-l+l*f:n[a]+i[a]-l-l*f];var h=c[u],p=c[a],d=t.fixed?"fixed":"absolute",v=(c[0]+o[0]>n[0]||c[0]2)switch(e.mode.charAt(2).toLowerCase()){case"s":return"s";case"v":return"v"}return null},onDocumentMouseDown:function(t){t||(t=window.event);var n=t.target||t.srcElement;n._jscLinkedInstance?n._jscLinkedInstance.showOnClick&&n._jscLinkedInstance.show():n._jscControlName?e.onControlPointerStart(t,n,n._jscControlName,"mouse"):e.picker&&e.picker.owner&&e.picker.owner.hide()},onDocumentTouchStart:function(t){t||(t=window.event);var n=t.target||t.srcElement;n._jscLinkedInstance?n._jscLinkedInstance.showOnClick&&n._jscLinkedInstance.show():n._jscControlName?e.onControlPointerStart(t,n,n._jscControlName,"touch"):e.picker&&e.picker.owner&&e.picker.owner.hide()},onWindowResize:function(t){e.redrawPosition()},onParentScroll:function(t){e.picker&&e.picker.owner&&e.picker.owner.hide()},_pointerMoveEvent:{mouse:"mousemove",touch:"touchmove"},_pointerEndEvent:{mouse:"mouseup",touch:"touchend"},_pointerOrigin:null,_capturedTarget:null,onControlPointerStart:function(t,n,r,i){var s=n._jscInstance;e.preventDefault(t),e.captureTarget(n);var o=function(s,o){e.attachGroupEvent("drag",s,e._pointerMoveEvent[i],e.onDocumentPointerMove(t,n,r,i,o)),e.attachGroupEvent("drag",s,e._pointerEndEvent[i],e.onDocumentPointerEnd(t,n,r,i))};o(document,[0,0]);if(window.parent&&window.frameElement){var u=window.frameElement.getBoundingClientRect(),a=[-u.left,-u.top];o(window.parent.window.document,a)}var f=e.getAbsPointerPos(t),l=e.getRelPointerPos(t);e._pointerOrigin={x:f.x-l.x,y:f.y-l.y};switch(r){case"pad":switch(e.getSliderComponent(s)){case"s":s.hsv[1]===0&&s.fromHSV(null,100,null);break;case"v":s.hsv[2]===0&&s.fromHSV(null,null,100)}e.setPad(s,t,0,0);break;case"sld":e.setSld(s,t,0)}e.dispatchFineChange(s)},onDocumentPointerMove:function(t,n,r,i,s){return function(t){var i=n._jscInstance;switch(r){case"pad":t||(t=window.event),e.setPad(i,t,s[0],s[1]),e.dispatchFineChange(i);break;case"sld":t||(t=window.event),e.setSld(i,t,s[1]),e.dispatchFineChange(i)}}},onDocumentPointerEnd:function(t,n,r,i){return function(t){var r=n._jscInstance;e.detachGroupEvents("drag"),e.releaseTarget(),e.dispatchChange(r)}},dispatchChange:function(t){t.valueElement&&e.isElementType(t.valueElement,"input")&&e.fireEvent(t.valueElement,"change")},dispatchFineChange:function(e){if(e.onFineChange){var t;typeof e.onFineChange=="string"?t=new Function(e.onFineChange):t=e.onFineChange,t.call(e)}},setPad:function(t,n,r,i){var s=e.getAbsPointerPos(n),o=r+s.x-e._pointerOrigin.x-t.padding-t.insetWidth,u=i+s.y-e._pointerOrigin.y-t.padding-t.insetWidth,a=o*(360/(t.width-1)),f=100-u*(100/(t.height-1));switch(e.getPadYComponent(t)){case"s":t.fromHSV(a,f,null,e.leaveSld);break;case"v":t.fromHSV(a,null,f,e.leaveSld)}},setSld:function(t,n,r){var i=e.getAbsPointerPos(n),s=r+i.y-e._pointerOrigin.y-t.padding-t.insetWidth,o=100-s*(100/(t.height-1));switch(e.getSliderComponent(t)){case"s":t.fromHSV(null,o,null,e.leavePad);break;case"v":t.fromHSV(null,null,o,e.leavePad)}},_vmlNS:"jsc_vml_",_vmlCSS:"jsc_vml_css_",_vmlReady:!1,initVML:function(){if(!e._vmlReady){var t=document;t.namespaces[e._vmlNS]||t.namespaces.add(e._vmlNS,"urn:schemas-microsoft-com:vml");if(!t.styleSheets[e._vmlCSS]){var n=["shape","shapetype","group","background","path","formulas","handles","fill","stroke","shadow","textbox","textpath","imagedata","line","polyline","curve","rect","roundrect","oval","arc","image"],r=t.createStyleSheet();r.owningElement.id=e._vmlCSS;for(var i=0;i=3&&(s=r[0].match(i))&&(o=r[1].match(i))&&(u=r[2].match(i))){var a=parseFloat((s[1]||"0")+(s[2]||"")),f=parseFloat((o[1]||"0")+(o[2]||"")),l=parseFloat((u[1]||"0")+(u[2]||""));return this.fromRGB(a,f,l,t),!0}}return!1},this.toString=function(){return(256|Math.round(this.rgb[0])).toString(16).substr(1)+(256|Math.round(this.rgb[1])).toString(16).substr(1)+(256|Math.round(this.rgb[2])).toString(16).substr(1)},this.toHEXString=function(){return"#"+this.toString().toUpperCase()},this.toRGBString=function(){return"rgb("+Math.round(this.rgb[0])+","+Math.round(this.rgb[1])+","+Math.round(this.rgb[2])+")"},this.isLight=function(){return.213*this.rgb[0]+.715*this.rgb[1]+.072*this.rgb[2]>127.5},this._processParentElementsInDOM=function(){if(this._linkedElementsProcessed)return;this._linkedElementsProcessed=!0;var t=this.targetElement;do{var n=e.getStyle(t);n&&n.position.toLowerCase()==="fixed"&&(this.fixed=!0),t!==this.targetElement&&(t._jscEventsAttached||(e.attachEvent(t,"scroll",e.onParentScroll),t._jscEventsAttached=!0))}while((t=t.parentNode)&&!e.isElementType(t,"body"))};if(typeof t=="string"){var h=t,p=document.getElementById(h);p?this.targetElement=p:e.warn("Could not find target element with ID '"+h+"'")}else t?this.targetElement=t:e.warn("Invalid target element: '"+t+"'");if(this.targetElement._jscLinkedInstance){e.warn("Cannot link jscolor twice to the same element. Skipping.");return}this.targetElement._jscLinkedInstance=this,this.valueElement=e.fetchElement(this.valueElement),this.styleElement=e.fetchElement(this.styleElement);var d=this,v=this.container?e.fetchElement(this.container):document.getElementsByTagName("body")[0],m=3;if(e.isElementType(this.targetElement,"button"))if(this.targetElement.onclick){var g=this.targetElement.onclick;this.targetElement.onclick=function(e){return g.call(this,e),!1}}else this.targetElement.onclick=function(){return!1};if(this.valueElement&&e.isElementType(this.valueElement,"input")){var y=function(){d.fromString(d.valueElement.value,e.leaveValue),e.dispatchFineChange(d)};e.attachEvent(this.valueElement,"keyup",y),e.attachEvent(this.valueElement,"input",y),e.attachEvent(this.valueElement,"blur",c),this.valueElement.setAttribute("autocomplete","off")}this.styleElement&&(this.styleElement._jscOrigStyle={backgroundImage:this.styleElement.style.backgroundImage,backgroundColor:this.styleElement.style.backgroundColor,color:this.styleElement.style.color}),this.value?this.fromString(this.value)||this.exportColor():this.importColor()}};return e.jscolor.lookupClass="jscolor",e.jscolor.installByClassName=function(t){var n=document.getElementsByTagName("input"),r=document.getElementsByTagName("button");e.tryInstallOnElements(n,t),e.tryInstallOnElements(r,t)},e.register(),e.jscolor}()); \ No newline at end of file diff --git a/style/app.scss b/style/app.scss index 9cf8e6eb2..4d610265a 100644 --- a/style/app.scss +++ b/style/app.scss @@ -100,25 +100,12 @@ $graph-overlay-side-margin: 15px; --nav-active-color: #deddbb; --timetable-border-color: #db94b8; --map-day-bg-color: #dedae5; - --draw-panel-color: #008080; - --draw-panel-hover-color: #28b0a2; --spotlight-fill-color: #feefc8; // hover over a course --spotlight-stroke-color: #ffbd8e; - // Draw-tool palette for /draw - --draw-swatch-1: #ff7878; - --draw-swatch-2: #ed9; - --draw-swatch-3: #9bd1fa; - --draw-swatch-4: #ffd1dc; - --draw-swatch-5: #ffc48c; - --draw-swatch-6: #bdecb6; - --draw-swatch-7: #e3aad6; - --draw-swatch-8: #ad876e; - --draw-swatch-9: #a2a9af; - // Greys --elevation-grey-color: #808080; // box-shadow tint on floating panels/buttons, and .highlight-nodes bg - --neutral-grey-color: #dcdcdc; // disabled states, draw-tool buttons, post-nav borders, reset-selections shadow + --neutral-grey-color: #dcdcdc; // disabled states, post-nav borders, reset-selections shadow --light-border-color: #c0c0c0; --disabled-text: #9c9c9c; --info-disabled-bg-color: #a0aec0; @@ -1392,51 +1379,6 @@ path.missing { background-color: var(--color-white); } -#colour-table { - height: 40px; - width: 200px; -} - -#colour-table tr:nth-child(1) td:nth-child(1) { - background: var(--draw-swatch-1); -} - -#colour-table tr:nth-child(1) td:nth-child(2) { - background: var(--draw-swatch-2); -} - -#colour-table tr:nth-child(1) td:nth-child(3) { - background: var(--draw-swatch-3); -} - -#colour-table tr:nth-child(1) td:nth-child(4) { - background: var(--draw-swatch-4); -} - -#colour-table tr:nth-child(1) td:nth-child(5) { - background: var(--color-white); -} - -#colour-table tr:nth-child(2) td:nth-child(1) { - background: var(--draw-swatch-5); -} - -#colour-table tr:nth-child(2) td:nth-child(2) { - background: var(--draw-swatch-6); -} - -#colour-table tr:nth-child(2) td:nth-child(3) { - background: var(--draw-swatch-7); -} - -#colour-table tr:nth-child(2) td:nth-child(4) { - background: var(--draw-swatch-8); -} - -#colour-table tr:nth-child(2) td:nth-child(5) { - background: var(--draw-swatch-9); -} - #main { border: solid 2px var(--color-black); border-radius: 8px; @@ -1446,80 +1388,6 @@ path.missing { width: 85%; } -#about-div { - font-size: 1.2em; - margin: 0 0 0 10px; -} - -#background { - /* background-image : url(/static/res/backgrounds/draw-background.png); */ - background-size: 8px; - height: 100%; - opacity: 0.3; - width: 100%; -} - -#mySVG { - height: 100%; - left: 0; - position: absolute; - top: 0; - width: 100%; -} - -#side-panel-wrap { - background-color: var(--draw-panel-color); - border: solid 2px var(--color-black); - border-radius: 8px; - float: left; - height: 85%; - overflow-y: auto; - padding: 5px 0; - width: 15%; -} - -.mode { - border: solid 2px var(--draw-panel-color); - border-radius: 8px; - font-size: 0.75em; - margin: 0 0 0 5px; - padding: 0 0 0 5px; - transition: all 0.2s; - width: 93%; -} - -.mode:hover { - background-color: var(--draw-panel-hover-color) !important; - color: var(--neutral-grey-color) !important; - cursor: pointer; -} - -.clicked.mode { - background-color: var(--draw-panel-hover-color) !important; -} - -.clicked { - border: solid 2px var(--color-black); - color: var(--neutral-grey-color) !important; -} - -.button { - border: solid 2px var(--color-black); - border-radius: 8px; - font-size: 0.75em; - margin: 5px; - padding: 0; - text-align: center; - transition: all 0.2s; - width: 40%; -} - -.button:hover { - background-color: var(--color-black) !important; - color: var(--neutral-grey-color) !important; - cursor: pointer; -} - input { border: solid 2px var(--neutral-grey-color); border-radius: 8px; @@ -1538,48 +1406,6 @@ input:focus { box-shadow: 0 0 3px 1px var(--input-focus-ring-color); } -#add-text { - display: inline; - margin: 5px; - padding: 2px 5px; - width: 45%; -} - -.mylabel { - dominant-baseline: central; - stroke: none; - text-align: center; - text-anchor: middle; - -webkit-touch-callout: none; - user-select: none; -} - -.elbow { - opacity: 0; -} - -.elbow:hover { - cursor: pointer; - opacity: 1; -} - -.rElbow { - opacity: 0; -} - -.rElbow:hover { - cursor: pointer; - opacity: 1; -} - -#finish-region { - background-color: var(--neutral-grey-color); - border: solid 2px var(--draw-panel-color); - margin: 5px; - padding: 0; - width: 40%; -} - i { color: var(--invalid-color); } diff --git a/webpack.common.js b/webpack.common.js index 425322b4c..2a7463e28 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -9,7 +9,6 @@ module.exports = { entry: { "js/grid/app": "./js/components/grid/main.js", "js/graph/app": "./js/components/graph/main.js", - "js/draw/app": "./js/components/draw/main.js", "js/generate/app": "./js/components/generate/generate.jsx", "js/about/app": "./js/components/about/about.js", "style/app": "./style/app.js",