diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..3cd5a5b Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40b878d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/3d_graph/background.jpg b/3d_graph/background.jpg new file mode 100644 index 0000000..675237a Binary files /dev/null and b/3d_graph/background.jpg differ diff --git a/3d_graph/canvas/background.js b/3d_graph/canvas/background.js new file mode 100644 index 0000000..e3fd872 --- /dev/null +++ b/3d_graph/canvas/background.js @@ -0,0 +1,14 @@ +let img; + +export function drawBackground(context) { + img = new Image(); + img.onload = function() { + context.drawImage(img, 0, -140, 800, 800); + }; + + img.src = './background.jpg'; +} + +export function refreshBackground(context) { + context.drawImage(img, 0, -140, 800, 800); +} \ No newline at end of file diff --git a/3d_graph/canvas/buttons.js b/3d_graph/canvas/buttons.js new file mode 100644 index 0000000..b64c90a --- /dev/null +++ b/3d_graph/canvas/buttons.js @@ -0,0 +1,108 @@ +export const addPointButton = { + rect: { + x: 820, + y: 60, + width: 140, + height: 30 + }, + title: { + x: 855, + y: 80, + text: 'Add Point', + alt: 'Adding...', + }, + clicked: false +}; + +export const addPathButton = { + rect: { + x: 820, + y: 20, + width: 140, + height: 30 + }, + title: { + x: 855, + y: 40, + text: 'Add Path', + alt: 'Adding...', + }, + clicked: false +}; + +export const resetButton = { + rect: { + x: 820, + y: 100, + width: 140, + height: 30 + }, + title: { + x: 870, + y: 120, + text: 'Reset', + }, + clicked: false, +}; + +export const exportButton = { + rect: { + x: 820, + y: 300, + width: 140, + height: 30 + }, + title: { + x: 870, + y: 320, + text: 'Export', + }, + clicked: false, +}; + +export const importButton = { + rect: { + x: 820, + y: 350, + width: 140, + height: 30 + }, + title: { + x: 870, + y: 370, + text: 'Import', + }, + clicked: false, +}; + +export const setStartButton = { + rect: { + x: 820, + y: 210, + width: 140, + height: 30 + }, + title: { + x: 870, + y: 230, + text: 'Set Start', + alt: 'Choose Start' + }, + clicked: false +}; + +export const setEndButton = { + rect: { + x: 820, + y: 250, + width: 140, + height: 30 + }, + title: { + x: 870, + y: 270, + text: 'Set End', + alt: 'Choose End' + }, + clicked: false, +}; \ No newline at end of file diff --git a/3d_graph/canvas/drawButton.js b/3d_graph/canvas/drawButton.js new file mode 100644 index 0000000..7339d0e --- /dev/null +++ b/3d_graph/canvas/drawButton.js @@ -0,0 +1,24 @@ +export function drawButton(context, button) { + context.save(); + context.beginPath(); + context.fillStyle = '#dddddd'; + context.strokeStyle = '#cdcdcd'; + context.rect( + button.rect.x, + button.rect.y, + button.rect.width, + button.rect.height + ); + context.fill(); + context.lineWidth = 2; + context.strokeStyle = '#cdcdcd'; + context.stroke(); + context.closePath(); + + context.fillStyle = "#333"; + context.font = '18px serif'; + + const title = !button.clicked ? button.title.text : button.title.alt; + context.fillText(title, button.title.x, button.title.y); + context.restore(); +} \ No newline at end of file diff --git a/3d_graph/canvas/drawMenu.js b/3d_graph/canvas/drawMenu.js new file mode 100644 index 0000000..0e4c43b --- /dev/null +++ b/3d_graph/canvas/drawMenu.js @@ -0,0 +1,5 @@ +import { drawButton } from './drawButton.js'; + +export function drawMenu(buttons, context) { + buttons.forEach(drawButton.bind(null, context)); +} \ No newline at end of file diff --git a/3d_graph/canvas/drawPoints.js b/3d_graph/canvas/drawPoints.js new file mode 100644 index 0000000..bc76523 --- /dev/null +++ b/3d_graph/canvas/drawPoints.js @@ -0,0 +1,20 @@ +export function drawPoint(context, point) { + context.beginPath(); + context.strokeStyle = (point.start || point.end) ? 'yellow' : point.highlight ? 'black' : 'red'; + context.fillStyle = 'white'; + context.arc(point.x, point.y, 5, 0, Math.PI * 2, true); // Outer circle + context.fill(); + context.stroke(); +} + +export function drawPoints(context, points) { + context.save(); + + context.fillStyle = "blue" + context.strokeStyle = "red"; + context.lineWidth = 3; + + points.forEach(drawPoint.bind(null, context)); + + context.restore(); +} \ No newline at end of file diff --git a/3d_graph/canvas/drawSegments.js b/3d_graph/canvas/drawSegments.js new file mode 100644 index 0000000..020195b --- /dev/null +++ b/3d_graph/canvas/drawSegments.js @@ -0,0 +1,32 @@ +export function drawSegments(mousePos, segments, context) { + if (!segments.length) { + return; + } + + console.log(`Drawing ${segments.length} segments`); + + const {x, y} = mousePos; + context.save(); + context.lineWidth = 5; + context.lineCap = "round"; + context.strokeStyle = "pink"; + + segments.forEach((segment) => { + context.beginPath(); + context.moveTo(segment.start.x, segment.start.y); + + segment.intermediates.forEach((intermediate) => { + context.lineTo(intermediate.x, intermediate.y); + }); + + const end = segment.end || { + x, + y + }; + + context.lineTo(end.x, end.y); + context.stroke(); + }); + + context.restore(); +} \ No newline at end of file diff --git a/3d_graph/canvas/handlers/onAddSegmentHandler.js b/3d_graph/canvas/handlers/onAddSegmentHandler.js new file mode 100644 index 0000000..9d768fa --- /dev/null +++ b/3d_graph/canvas/handlers/onAddSegmentHandler.js @@ -0,0 +1,70 @@ +import { isInside } from '../isInside.js'; + +let selectedPoint; + +function getPointUnderCursor(points, mousePos) { + return points.find((point) => { + const rect = { + x: point.x - 2.5, + y: point.y - 2.5, + width: 8, + height: 8 + }; + + return isInside(mousePos, rect); + }); +} + +function highlightFirstPointOfSegment(mousePos, points) { + const pointUnderCursor = getPointUnderCursor(points, mousePos); + + if (!pointUnderCursor) { + return null; + } + + selectedPoint = true; + + return { + start: pointUnderCursor, + intermediates: [], + end: null + }; +} + +function attemptToJoinToOpenSegment(mousePos, points) { + const pointUnderCursor = getPointUnderCursor(points, mousePos); + + if (!pointUnderCursor) { + return null; + } + + return pointUnderCursor; +} + +export function onAddSegmentHandler(mousePos, segments, points) { + if (!selectedPoint) { + const segment = highlightFirstPointOfSegment(mousePos, points); + + if (segment) { + console.log(`Added segment`); + segments.push(segment); + } + + return segments; + } + + const point = attemptToJoinToOpenSegment(mousePos, points); + + if (point) { + console.log(`Added segment end`); + segments[segments.length - 1].end = point; + selectedPoint = false; + } else { + console.log(`Added segment middle`); + segments[segments.length - 1].intermediates.push({ + ...mousePos + }); + } + + return segments; +} \ No newline at end of file diff --git a/3d_graph/canvas/handlers/onClickHandler.js b/3d_graph/canvas/handlers/onClickHandler.js new file mode 100644 index 0000000..4f981d1 --- /dev/null +++ b/3d_graph/canvas/handlers/onClickHandler.js @@ -0,0 +1,36 @@ + +import { drawPoints } from '../drawPoints.js'; +import { isInside } from '../isInside.js'; + +function alreadyAtPoint(points, mousePos) { + return points.find((point, index) => { + const rect = { + x: point.x - 2.5, + y: point.y - 2.5, + width: 8, + height: 8 + }; + + return isInside(mousePos, rect); + }); +} + +export function onAddPointHandler(mousePos, points, context) { + if (alreadyAtPoint(points, mousePos)) { + return points; + } + + const {x, y} = mousePos; + + console.log(`Add point Click at X: ${x} Y: ${y}`, 10, 20); + + points.push({ + x, + y, + highlight: false, + }); + + drawPoints(context, points); + + return points; +} \ No newline at end of file diff --git a/3d_graph/canvas/handlers/onSetEndHandler.js b/3d_graph/canvas/handlers/onSetEndHandler.js new file mode 100644 index 0000000..1272595 --- /dev/null +++ b/3d_graph/canvas/handlers/onSetEndHandler.js @@ -0,0 +1,40 @@ + +import { drawPoints } from '../drawPoints.js'; +import { isInside } from '../isInside.js'; + +function alreadyAtPoint(points, mousePos) { + return points.find((point, index) => { + const rect = { + x: point.x - 2.5, + y: point.y - 2.5, + width: 8, + height: 8 + }; + + return isInside(mousePos, rect); + }); +} + +export function onSetEndHandler(mousePos, points, context) { + const hit = alreadyAtPoint(points, mousePos); + + if (!hit) { + return points + } + + const {x, y} = mousePos; + + console.log(`End selected at X: ${x} Y: ${y}`, 10, 20); + + points = points.map((point, index) => { + point.end = false; + + return point; + }); + + hit.end = true; + + drawPoints(context, points); + + return points; +} \ No newline at end of file diff --git a/3d_graph/canvas/handlers/onSetStartHandler.js b/3d_graph/canvas/handlers/onSetStartHandler.js new file mode 100644 index 0000000..6920bc5 --- /dev/null +++ b/3d_graph/canvas/handlers/onSetStartHandler.js @@ -0,0 +1,40 @@ + +import { drawPoints } from '../drawPoints.js'; +import { isInside } from '../isInside.js'; + +function alreadyAtPoint(points, mousePos) { + return points.find((point, index) => { + const rect = { + x: point.x - 2.5, + y: point.y - 2.5, + width: 8, + height: 8 + }; + + return isInside(mousePos, rect); + }); +} + +export function onSetStartHandler(mousePos, points, context) { + const hit = alreadyAtPoint(points, mousePos); + + if (!hit) { + return points + } + + const {x, y} = mousePos; + + console.log(`Start selected at X: ${x} Y: ${y}`, 10, 20); + + points = points.map((point, index) => { + point.start = false; + + return point; + }); + + hit.start = true; + + drawPoints(context, points); + + return points; +} \ No newline at end of file diff --git a/3d_graph/canvas/isInside.js b/3d_graph/canvas/isInside.js new file mode 100644 index 0000000..2e033f8 --- /dev/null +++ b/3d_graph/canvas/isInside.js @@ -0,0 +1,6 @@ +export function isInside(pos, rect) { + return pos.x > rect.x && + pos.x < rect.x + rect.width && + pos.y < rect.y + rect.height && + pos.y > rect.y; +} \ No newline at end of file diff --git a/3d_graph/canvas/isMenuArea.js b/3d_graph/canvas/isMenuArea.js new file mode 100644 index 0000000..39df72f --- /dev/null +++ b/3d_graph/canvas/isMenuArea.js @@ -0,0 +1,3 @@ +export default function isMenuArea(x, y) { + return x > 800 || y > 657; +} \ No newline at end of file diff --git a/3d_graph/canvas/mouse/mousePosition.js b/3d_graph/canvas/mouse/mousePosition.js new file mode 100644 index 0000000..e80c4d9 --- /dev/null +++ b/3d_graph/canvas/mouse/mousePosition.js @@ -0,0 +1,8 @@ +export function mousePosition(canvas, event) { + var rect = canvas.getBoundingClientRect(); + + return { + x: event.clientX - rect.left, + y: event.clientY - rect.top + }; +} \ No newline at end of file diff --git a/3d_graph/canvas/mouse/onMouseOver.js b/3d_graph/canvas/mouse/onMouseOver.js new file mode 100644 index 0000000..256c993 --- /dev/null +++ b/3d_graph/canvas/mouse/onMouseOver.js @@ -0,0 +1,47 @@ +import { mousePosition } from '../mouse/mousePosition.js'; +import { refreshBackground} from '../background.js'; +import { drawPoints } from '../drawPoints.js'; +import { drawMenu } from '../drawMenu.js'; +import { drawSegments } from '../drawSegments.js'; +import { isInside } from '../isInside.js'; + +function drawPosition(context, x, y) { + context.save(); + context.fillStyle = "#000000"; + context.font = '12px serif'; + context.fillText(`X: ${x} Y: ${y}`, 10, 20); + context.restore(); +} + +function markHighlighthedPoints(points, mousePos) { + return points.map((point, index) => { + const rect = { + x: point.x - 2.5, + y: point.y - 2.5, + width: 8, + height: 8 + }; + + point.highlight = isInside(mousePos, rect); + + if (point.highlight) { + console.log(`Over: ${index}`); + } + + return point; + }); +} + +export function onMouseOver(canvas, context, buttons, segments, points, e) { + refreshBackground(context); + + const mousePos = mousePosition(canvas, e); + const {x, y} = mousePos; + const highlightedPoints = markHighlighthedPoints(points, mousePos); + + drawSegments(mousePos, segments, context); + drawPoints(context, highlightedPoints); + drawMenu(buttons, context); + + drawPosition(context, x, y); +} \ No newline at end of file diff --git a/3d_graph/dijkstras.js b/3d_graph/dijkstras.js new file mode 100644 index 0000000..7096f7e --- /dev/null +++ b/3d_graph/dijkstras.js @@ -0,0 +1,87 @@ +function shortestDistanceNode(distances, visited) { + let shortest = null; + + for (let node in distances) { + let currentIsShortest = shortest === null || distances[node] < distances[shortest]; + + if (currentIsShortest && !visited.includes(node)) { + shortest = node; + } + } + + return shortest; +} + +export default function findShortestPath(graph, startNode, endNode) { + + // track distances from the start node using a hash object + let distances = {}; + + distances[endNode] = "Infinity"; + distances = Object.assign(distances, graph[startNode]); + + // track paths using a hash object + let parents = { endNode: null }; + + for (let child in graph[startNode]) { + parents[child] = startNode; + } + + // collect visited nodes + let visited = []; + // find the nearest node + let node = shortestDistanceNode(distances, visited); + + // for that node: + while (node) { + // find its distance from the start node & its child nodes + let distance = distances[node]; + let children = graph[node]; + + // for each of those child nodes: + for (let child in children) { + + // make sure each child node is not the start node + if (String(child) === String(startNode)) { + continue; + } else { + // save the distance from the start node to the child node + let newDistance = distance + children[child]; + // if there's no recorded distance from the start node to the child node in the distances object + // or if the recorded distance is shorter than the previously stored distance from the start node to the child node + if (!distances[child] || distances[child] > newDistance) { + // save the distance to the object + distances[child] = newDistance; + // record the path + parents[child] = node; + } + } + } + + // move the current node to the visited set + visited.push(node); + // move to the nearest neighbor node + node = shortestDistanceNode(distances, visited); + } + + // using the stored paths from start node to end node + // record the shortest path + let shortestPath = [endNode]; + let parent = parents[endNode]; + + while (parent) { + shortestPath.push(parent); + parent = parents[parent]; + } + + shortestPath.reverse(); + + //this is the shortest path + let results = { + distance: distances[endNode], + path: shortestPath, + }; + + // return the shortest path & the end node's distance from the start node + return results; +} \ No newline at end of file diff --git a/3d_graph/export.json b/3d_graph/export.json new file mode 100644 index 0000000..57e7f57 --- /dev/null +++ b/3d_graph/export.json @@ -0,0 +1,871 @@ +{ + "points": [ + { + "x": 558, + "y": 104, + "highlight": false + }, + { + "x": 556, + "y": 144, + "highlight": false + }, + { + "x": 641, + "y": 102, + "highlight": false + }, + { + "x": 603, + "y": 204, + "highlight": false + }, + { + "x": 507, + "y": 204, + "highlight": false + }, + { + "x": 465, + "y": 146, + "highlight": false + }, + { + "x": 457, + "y": 103, + "highlight": false + }, + { + "x": 360, + "y": 200, + "highlight": false + }, + { + "x": 332, + "y": 252, + "highlight": false + }, + { + "x": 416, + "y": 257, + "highlight": false + }, + { + "x": 394, + "y": 284, + "highlight": false + }, + { + "x": 394, + "y": 318, + "highlight": false + }, + { + "x": 482, + "y": 315, + "highlight": false + }, + { + "x": 497, + "y": 240, + "highlight": false + }, + { + "x": 514, + "y": 314, + "highlight": false + }, + { + "x": 575, + "y": 290, + "highlight": false + }, + { + "x": 602, + "y": 318, + "highlight": false + }, + { + "x": 624, + "y": 292, + "highlight": false + }, + { + "x": 465, + "y": 359, + "highlight": false + }, + { + "x": 369, + "y": 338, + "highlight": false + }, + { + "x": 306, + "y": 308, + "highlight": false + }, + { + "x": 334, + "y": 281, + "highlight": false + }, + { + "x": 301, + "y": 284, + "highlight": false + }, + { + "x": 276, + "y": 327, + "highlight": false + }, + { + "x": 258, + "y": 345, + "highlight": false + }, + { + "x": 277, + "y": 364, + "highlight": false + }, + { + "x": 277, + "y": 408, + "highlight": false + }, + { + "x": 162, + "y": 462, + "highlight": false + }, + { + "x": 318, + "y": 453, + "highlight": false + }, + { + "x": 318, + "y": 434, + "highlight": false + }, + { + "x": 387, + "y": 432, + "highlight": false + }, + { + "x": 361, + "y": 455, + "highlight": false + }, + { + "x": 390, + "y": 455, + "highlight": false + }, + { + "x": 412, + "y": 479, + "highlight": false + }, + { + "x": 446, + "y": 599, + "highlight": false + }, + { + "x": 385, + "y": 507, + "highlight": false + }, + { + "x": 540, + "y": 202, + "highlight": false + } + ], + "segments": [ + { + "start": { + "x": 641, + "y": 102, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 558, + "y": 104, + "highlight": false + } + }, + { + "start": { + "x": 558, + "y": 104, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 556, + "y": 144, + "highlight": false + } + }, + { + "start": { + "x": 556, + "y": 144, + "highlight": false + }, + "intermediates": [ + { + "x": 542, + "y": 163 + } + ], + "end": { + "x": 540, + "y": 202, + "highlight": false + } + }, + { + "start": { + "x": 540, + "y": 202, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 603, + "y": 204, + "highlight": false + } + }, + { + "start": { + "x": 540, + "y": 202, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 507, + "y": 204, + "highlight": false + } + }, + { + "start": { + "x": 507, + "y": 204, + "highlight": false + }, + "intermediates": [ + { + "x": 500, + "y": 181 + } + ], + "end": { + "x": 465, + "y": 146, + "highlight": false + } + }, + { + "start": { + "x": 465, + "y": 146, + "highlight": false + }, + "intermediates": [ + { + "x": 459, + "y": 127 + } + ], + "end": { + "x": 457, + "y": 103, + "highlight": false + } + }, + { + "start": { + "x": 457, + "y": 103, + "highlight": false + }, + "intermediates": [ + { + "x": 430, + "y": 104 + }, + { + "x": 360, + "y": 176 + } + ], + "end": { + "x": 360, + "y": 200, + "highlight": false + } + }, + { + "start": { + "x": 360, + "y": 200, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 416, + "y": 257, + "highlight": false + } + }, + { + "start": { + "x": 416, + "y": 257, + "highlight": false + }, + "intermediates": [ + { + "x": 441, + "y": 236 + }, + { + "x": 441, + "y": 216 + }, + { + "x": 465, + "y": 191 + } + ], + "end": { + "x": 465, + "y": 146, + "highlight": false + } + }, + { + "start": { + "x": 416, + "y": 257, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 394, + "y": 284, + "highlight": false + } + }, + { + "start": { + "x": 360, + "y": 200, + "highlight": false + }, + "intermediates": [ + { + "x": 351, + "y": 226 + }, + { + "x": 340, + "y": 234 + } + ], + "end": { + "x": 332, + "y": 252, + "highlight": false + } + }, + { + "start": { + "x": 332, + "y": 252, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 334, + "y": 281, + "highlight": false + } + }, + { + "start": { + "x": 334, + "y": 281, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 301, + "y": 284, + "highlight": false + } + }, + { + "start": { + "x": 334, + "y": 281, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 306, + "y": 308, + "highlight": false + } + }, + { + "start": { + "x": 334, + "y": 281, + "highlight": false + }, + "intermediates": [ + { + "x": 368, + "y": 316 + } + ], + "end": { + "x": 369, + "y": 338, + "highlight": false + } + }, + { + "start": { + "x": 369, + "y": 338, + "highlight": false + }, + "intermediates": [ + { + "x": 306, + "y": 342 + } + ], + "end": { + "x": 277, + "y": 364, + "highlight": false + } + }, + { + "start": { + "x": 277, + "y": 364, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 258, + "y": 345, + "highlight": false + } + }, + { + "start": { + "x": 258, + "y": 345, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 276, + "y": 327, + "highlight": false + } + }, + { + "start": { + "x": 277, + "y": 364, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 277, + "y": 408, + "highlight": false + } + }, + { + "start": { + "x": 277, + "y": 408, + "highlight": false + }, + "intermediates": [ + { + "x": 197, + "y": 414 + }, + { + "x": 197, + "y": 461 + } + ], + "end": { + "x": 162, + "y": 462, + "highlight": false + } + }, + { + "start": { + "x": 277, + "y": 408, + "highlight": false + }, + "intermediates": [ + { + "x": 282, + "y": 432 + } + ], + "end": { + "x": 318, + "y": 434, + "highlight": false + } + }, + { + "start": { + "x": 318, + "y": 434, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 387, + "y": 432, + "highlight": false + } + }, + { + "start": { + "x": 387, + "y": 432, + "highlight": false + }, + "intermediates": [ + { + "x": 389, + "y": 376 + }, + { + "x": 369, + "y": 375 + } + ], + "end": { + "x": 369, + "y": 338, + "highlight": false + } + }, + { + "start": { + "x": 369, + "y": 338, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 394, + "y": 318, + "highlight": false + } + }, + { + "start": { + "x": 394, + "y": 284, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 394, + "y": 318, + "highlight": false + } + }, + { + "start": { + "x": 394, + "y": 318, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 482, + "y": 315, + "highlight": false + } + }, + { + "start": { + "x": 482, + "y": 315, + "highlight": false + }, + "intermediates": [ + { + "x": 486, + "y": 266 + }, + { + "x": 497, + "y": 256 + } + ], + "end": { + "x": 497, + "y": 240, + "highlight": false + } + }, + { + "start": { + "x": 497, + "y": 240, + "highlight": false + }, + "intermediates": [ + { + "x": 506, + "y": 230 + } + ], + "end": { + "x": 507, + "y": 204, + "highlight": false + } + }, + { + "start": { + "x": 624, + "y": 292, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 575, + "y": 290, + "highlight": false + } + }, + { + "start": { + "x": 575, + "y": 290, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 602, + "y": 318, + "highlight": false + } + }, + { + "start": { + "x": 575, + "y": 290, + "highlight": false + }, + "intermediates": [ + { + "x": 546, + "y": 291 + }, + { + "x": 531, + "y": 312 + } + ], + "end": { + "x": 514, + "y": 314, + "highlight": false + } + }, + { + "start": { + "x": 514, + "y": 314, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 482, + "y": 315, + "highlight": false + } + }, + { + "start": { + "x": 482, + "y": 315, + "highlight": false + }, + "intermediates": [ + { + "x": 483, + "y": 328 + }, + { + "x": 466, + "y": 346 + } + ], + "end": { + "x": 465, + "y": 359, + "highlight": false + } + }, + { + "start": { + "x": 465, + "y": 359, + "highlight": false + }, + "intermediates": [ + { + "x": 430, + "y": 360 + }, + { + "x": 407, + "y": 339 + } + ], + "end": { + "x": 369, + "y": 338, + "highlight": false + } + }, + { + "start": { + "x": 465, + "y": 359, + "highlight": false + }, + "intermediates": [ + { + "x": 463, + "y": 403 + }, + { + "x": 433, + "y": 433 + } + ], + "end": { + "x": 387, + "y": 432, + "highlight": false + } + }, + { + "start": { + "x": 318, + "y": 434, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 318, + "y": 453, + "highlight": false + } + }, + { + "start": { + "x": 318, + "y": 453, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 361, + "y": 455, + "highlight": false + } + }, + { + "start": { + "x": 361, + "y": 455, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 390, + "y": 455, + "highlight": false + } + }, + { + "start": { + "x": 390, + "y": 455, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 412, + "y": 479, + "highlight": false + } + }, + { + "start": { + "x": 412, + "y": 479, + "highlight": false + }, + "intermediates": [], + "end": { + "x": 385, + "y": 507, + "highlight": false + } + }, + { + "start": { + "x": 412, + "y": 479, + "highlight": false + }, + "intermediates": [ + { + "x": 482, + "y": 552 + } + ], + "end": { + "x": 446, + "y": 599, + "highlight": false + } + } + ] +} \ No newline at end of file diff --git a/3d_graph/index.html b/3d_graph/index.html new file mode 100644 index 0000000..d54d115 --- /dev/null +++ b/3d_graph/index.html @@ -0,0 +1,11 @@ + +
+ + + + \ No newline at end of file diff --git a/3d_graph/main.js b/3d_graph/main.js new file mode 100644 index 0000000..e9045a0 --- /dev/null +++ b/3d_graph/main.js @@ -0,0 +1,126 @@ +import findShortestPath from './dijkstras.js'; +import { drawPoints } from './canvas/drawPoints.js'; +import { addPathButton, resetButton, addPointButton, exportButton, importButton, setStartButton, setEndButton } from './canvas/buttons.js'; +import { mousePosition } from './canvas/mouse/mousePosition.js'; +import { isInside } from './canvas/isInside.js'; +import isMenuArea from './canvas/isMenuArea.js'; +import { onAddPointHandler } from './canvas/handlers/onClickHandler.js'; +import { onAddSegmentHandler } from './canvas/handlers/onAddSegmentHandler.js'; +import { onSetStartHandler } from './canvas/handlers/onSetStartHandler.js'; +import { onSetEndHandler } from './canvas/handlers/onSetEndHandler.js'; +import { onMouseOver } from './canvas/mouse/onMouseOver.js'; +import { drawBackground, refreshBackground} from './canvas/background.js'; +import { drawMenu } from './canvas/drawMenu.js'; +import { drawSegments } from './canvas/drawSegments.js'; + +let img; +let canvas; +let context; +let segments = []; +let points = []; + +const buttons = [ + addPathButton, + resetButton, + addPointButton, + exportButton, + importButton, + setStartButton, + setEndButton +]; + +const statefulButtons = [ + addPathButton, + addPointButton, + setStartButton, + setEndButton +]; + +function setupMouseOver() { + canvas.onmousemove = function(e) { + onMouseOver(canvas, context, buttons, segments, points, e); + }; +} + +function setupMouseClick() { + canvas.addEventListener('click', function(e) { + const mousePos = mousePosition(canvas, e); + const {x, y} = mousePos; + + if (isMenuArea(x, y)) { + let inside = false; + + statefulButtons.forEach((button) => { + if (isInside(mousePos, button.rect)) { + button.clicked = !button.clicked; + inside = true + } else { + button.clicked = false; + } + }); + + if (inside) { + return drawMenu(buttons, context); + } + + if (isInside(mousePos, resetButton.rect)) { + addPathButton.clicked = false + points = []; + segments = []; + + refreshBackground(context); + drawPoints(context, points); + drawMenu(buttons, context); + + return; + } else if (isInside(mousePos, exportButton.rect)) { + window.plan = JSON.stringify({ + points, + segments + }); + + console.log(window.plan); + + return; + } else if (isInside(mousePos, importButton.rect)) { + const importedData = window.plan; + + points = importedData.points || []; + segments = importedData.segments || []; + + drawSegments(mousePos, segments, context); + drawPoints(context, points); + + return; + } + } + + if (addPointButton.clicked) { + points = onAddPointHandler(mousePos, points, context); + } else if (addPathButton.clicked) { + segments = onAddSegmentHandler(mousePos, segments, points, context); + drawSegments(mousePos, segments, context); + } else if (setStartButton.clicked) { + onSetStartHandler(mousePos, points, context); + setStartButton.clicked = false; + + drawMenu(buttons, context); + } else if (setEndButton.clicked) { + onSetEndHandler(mousePos, points, context); + setEndButton.clicked = false; + + drawMenu(buttons, context); + } + + }, false); +} + +export function main() { + canvas = document.getElementById('canvas'); + context = canvas.getContext('2d'); + + drawBackground(context); + setupMouseOver(); + setupMouseClick(); + drawMenu(buttons, context); +} \ No newline at end of file diff --git a/README.md b/README.md index cc5f720..5e339b4 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,12 @@ HTML5-canvas-projects ## HTML-5 Cannvas Project -We code many things including simple thermometer, speedometer, map and compass using Javascript, HTML, CSS and more! +We code many things including simple clock, timer, map, chess, thermometer, speedometer, map and compass using Javascript, HTML, CSS and more! + +To run with node: + +``` +npx http-server ./ +``` Happy Coding :D diff --git a/analogue_clock/analogue_clock.html b/analogue_clock/index.html similarity index 100% rename from analogue_clock/analogue_clock.html rename to analogue_clock/index.html diff --git a/bounce/sources/background.png b/bounce/background.png similarity index 100% rename from bounce/sources/background.png rename to bounce/background.png diff --git a/bounce/sources/bounce.js b/bounce/bounce.js similarity index 100% rename from bounce/sources/bounce.js rename to bounce/bounce.js diff --git a/bounce/sources/bouncing-letters.png b/bounce/bouncing-letters.png similarity index 100% rename from bounce/sources/bouncing-letters.png rename to bounce/bouncing-letters.png diff --git a/bounce/sources/google-bouncing-logo-theory.png b/bounce/google-bouncing-logo-theory.png similarity index 100% rename from bounce/sources/google-bouncing-logo-theory.png rename to bounce/google-bouncing-logo-theory.png diff --git a/bounce/sources/google-logo-photoshop-tutorial.png b/bounce/google-logo-photoshop-tutorial.png similarity index 100% rename from bounce/sources/google-logo-photoshop-tutorial.png rename to bounce/google-logo-photoshop-tutorial.png diff --git a/bounce/sources/index.html b/bounce/index.html similarity index 100% rename from bounce/sources/index.html rename to bounce/index.html diff --git a/bounce/jstestdriver/JsTestDriver-1.3.5.jar b/bounce/jstestdriver/JsTestDriver-1.3.5.jar deleted file mode 100644 index fda4866..0000000 Binary files a/bounce/jstestdriver/JsTestDriver-1.3.5.jar and /dev/null differ diff --git a/bounce/jstestdriver/TEST-Chrome_260141043_Windows.bounceTest.xml b/bounce/jstestdriver/TEST-Chrome_260141043_Windows.bounceTest.xml deleted file mode 100644 index aa07806..0000000 --- a/bounce/jstestdriver/TEST-Chrome_260141043_Windows.bounceTest.xml +++ /dev/null @@ -1,3 +0,0 @@ -