

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.