lab17
subdirectory of your personal repo, the other submits a file report.txt
in the lab17
subdirectory of your personal repo.lab17
directory, make three files
graphed.html
:
<html xmlns='http://www.w3.org/1999/xhtml'> <head> <meta http-equiv='content-type' content='text/html; charset=UTF-8'/> <title>Graph Editor</title> <link href='graphed.css' rel='stylesheet' type='text/css'/> <script src='graphed.js' type='text/javascript'></script> </head> <body> <div> <svg id='graphpanel' xmlns='http://www.w3.org/2000/svg'></svg> </div> </body> </html>
graphed.js
:
'use strict' function createCircleNode (x, y, size, color) { return { getBounds: () => { return { x: x, y: y, width: size, height: size } }, contains: p => { return (x + size / 2 - p.x) ** 2 + (y + size / 2 - p.y) ** 2 <= size ** 2 / 4 }, translate: (dx, dy) => { x += dx y += dy }, draw: () => { const panel = document.getElementById('graphpanel') const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle') circle.setAttribute('cx', x + size / 2) circle.setAttribute('cy', y + size / 2) circle.setAttribute('r', size / 2) circle.setAttribute('fill', color) panel.appendChild(circle) } } } class Graph { constructor() { this.nodes = [] this.edges = [] } add(n) { this.nodes.push(n) } findNode(p) { for (let i = this.nodes.length - 1; i >= 0; i--) { const n = this.nodes[i] if (n.contains(p)) return n } return undefined } draw() { for (const n of this.nodes) { n.draw() } } } document.addEventListener('DOMContentLoaded', function () { const graph = new Graph() const n1 = createCircleNode(10, 10, 20, 'goldenrod') const n2 = createCircleNode(30, 30, 20, 'blue') graph.add(n1) graph.add(n2) graph.draw() })
graphed.css
:
#graphpanel { border: solid black thin; }
graphed.html
in your web browser (Chrome or Firefox). What happens?graphed.js
(e.g. misspell grahp
somewhere). Reload the page. What happens?draw
method of the Graph
“class”. Refresh the page. What happens?oodp3code/ch08/graphed2/GraphPanel.java
. It has a mouse listener for selecting nodes. We want to implement this in JavaScript.function drawGrabber(x, y) { const size = 5; ... }to the top of
graphed.js
. Draw a single black rectangle with center (x, y). Follow the draw
method of a circle node. Test your method by adding the following to the end of the DOMContentLoaded
listener:
const bounds = n1.getBounds() drawGrabber(bounds.x, bounds.y) drawGrabber(bounds.x + bounds.width, bounds.y) drawGrabber(bounds.x, bounds.y + bounds.height) drawGrabber(bounds.x + bounds.width, bounds.y + bounds.height)Remove those test lines when you are done.
DOMContentLoaded
listener:
function mouseLocation(event) { const rect = panel.getBoundingClientRect(); return { x: event.clientX - rect.left, y: event.clientY - rect.top, } } const panel = document.getElementById('graphpanel') panel.addEventListener('mousedown', event => { let mousePoint = mouseLocation(event) let selected = ... if (...) { const bounds = selected.getBounds() drawGrabber(bounds.x, bounds.y) drawGrabber(bounds.x + bounds.width, bounds.y) drawGrabber(bounds.x, bounds.y + bounds.height) drawGrabber(bounds.x + bounds.width, bounds.y + bounds.height) } })Fill in the missing parts, looking at
GraphPanel.java
. What happens when you click on a node? On both nodes?function repaint() { panel.innerHTML = '' graph.draw() if (selected !== undefined) { const bounds = selected.getBounds() drawGrabber(bounds.x, bounds.y) drawGrabber(bounds.x + bounds.width, bounds.y) drawGrabber(bounds.x, bounds.y + bounds.height) drawGrabber(bounds.x + bounds.width, bounds.y + bounds.height) } }Now you should be able to select one or the other node, or deselect both.
mousemove
listener. In JavaScript, there are no separate methods for mouse moving and dragging. To tell that it was a drag, set a variable dragStartPoint
in mousedown
, set it to undefined in mouseup
, and check it in mousemove
. If it was set, the mouse is being dragged.mousedown
, you need to transform the event coordinates. mousemove
that GraphPanel.java
does.