commit
205617ecb3
@ -0,0 +1,28 @@
|
|||||||
|
circle {
|
||||||
|
r:5;
|
||||||
|
fill: black;
|
||||||
|
transition: r 0.5s linear, fill 0.5s linear; /* add this transition to original code */
|
||||||
|
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
overflow:visible;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 20px 40px;
|
||||||
|
}
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding:10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
/* add this css for the hover state */
|
||||||
|
circle:hover {
|
||||||
|
r:10;
|
||||||
|
fill: blue;
|
||||||
|
}
|
||||||
|
circle:active {
|
||||||
|
fill: red;
|
||||||
|
}
|
||||||
@ -0,0 +1,137 @@
|
|||||||
|
const WIDTH = 800;
|
||||||
|
const HEIGHT = 600;
|
||||||
|
let runs = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
date: 'October 1, 2017 at 4:00PM',
|
||||||
|
distance: 5.2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
date: 'October 2, 2017 at 5:00PM',
|
||||||
|
distance: 7.0725
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
date: 'October 3, 2017 at 6:00PM',
|
||||||
|
distance: 8.7
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
d3.select('svg')
|
||||||
|
.style('width', WIDTH)
|
||||||
|
.style('height', HEIGHT);
|
||||||
|
|
||||||
|
const parseTime = d3.timeParse("%B%e, %Y at %-I:%M%p");
|
||||||
|
const formatTime = d3.timeFormat("%B%e, %Y at %-I:%M%p");
|
||||||
|
const xScale = d3.scaleTime();
|
||||||
|
xScale.range([0,WIDTH]);
|
||||||
|
const xDomain = d3.extent(runs, (datum, index) => {
|
||||||
|
return parseTime(datum.date);
|
||||||
|
});
|
||||||
|
xScale.domain(xDomain);
|
||||||
|
|
||||||
|
const yScale = d3.scaleLinear(); //create the scale
|
||||||
|
yScale.range([HEIGHT, 0]); //set the visual range (e.g. 600 to 0)
|
||||||
|
const yDomain = d3.extent(runs, (datum, index) => {
|
||||||
|
return datum.distance; //compare distance properties of each item in the data array
|
||||||
|
})
|
||||||
|
yScale.domain(yDomain);
|
||||||
|
|
||||||
|
const render = () => {
|
||||||
|
|
||||||
|
//adjust the code at the top of your render function
|
||||||
|
d3.select('#points').html(''); //clear out all circles when rendering
|
||||||
|
d3.select('#points').selectAll('circle') //add circles to #points group, not svg
|
||||||
|
.data(runs)
|
||||||
|
.enter()
|
||||||
|
.append('circle');
|
||||||
|
|
||||||
|
d3.selectAll('circle').data(runs)
|
||||||
|
.attr('cy', (datum, index) => {
|
||||||
|
return yScale(datum.distance);
|
||||||
|
});
|
||||||
|
|
||||||
|
d3.selectAll('circle')
|
||||||
|
.attr('cx', (datum, index) => {
|
||||||
|
return xScale(parseTime(datum.date)); //use parseTime to convert the date string property on the datum object to a Date object, which xScale then converts to a visual value
|
||||||
|
});
|
||||||
|
|
||||||
|
//put this at the bottom of the render function, so that click handlers are attached when the circle is created
|
||||||
|
d3.selectAll('circle').on('click', (event, datum) => {
|
||||||
|
event.stopPropagation(); //stop click event from propagating to the SVG element and creating a run
|
||||||
|
runs = runs.filter((run, index) => { //create a new array that has removed the run with the correct id. Set it to the runs var
|
||||||
|
return run.id != datum.id;
|
||||||
|
});
|
||||||
|
render(); //re-render dots
|
||||||
|
createTable(); //re-render table
|
||||||
|
});
|
||||||
|
|
||||||
|
const drag = function(event, datum) {
|
||||||
|
const x = event.x;
|
||||||
|
const y = event.y;
|
||||||
|
d3.select(this).attr('cx', x);
|
||||||
|
d3.select(this).attr('cy', y);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dragEnd = (event, datum) => {
|
||||||
|
const x = event.x;
|
||||||
|
const y = event.y;
|
||||||
|
|
||||||
|
const date = xScale.invert(x);
|
||||||
|
const distance = yScale.invert(y);
|
||||||
|
|
||||||
|
datum.date = formatTime(date);
|
||||||
|
datum.distance = distance;
|
||||||
|
createTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
const dragBehavior = d3.drag()
|
||||||
|
.on('drag', drag)
|
||||||
|
.on('end', dragEnd);
|
||||||
|
d3.selectAll('circle').call(dragBehavior);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render();
|
||||||
|
|
||||||
|
const bottomAxis = d3.axisBottom(xScale); //pass the appropriate scale in as a parameter
|
||||||
|
d3.select('svg')
|
||||||
|
.append('g') //put everything inside a group
|
||||||
|
.call(bottomAxis) //generate the axis within the group
|
||||||
|
.attr('transform', 'translate(0,'+HEIGHT+')'); //move it to the bottom
|
||||||
|
|
||||||
|
const leftAxis = d3.axisLeft(yScale);
|
||||||
|
d3.select('svg')
|
||||||
|
.append('g')
|
||||||
|
.call(leftAxis); //no need to transform, since it's placed correctly initially
|
||||||
|
|
||||||
|
const createTable = () => {
|
||||||
|
d3.select('tbody').html(''); //clear out all rows from the table
|
||||||
|
for (let i = 0; i < runs.length; i++) {
|
||||||
|
const row = d3.select('tbody').append('tr');
|
||||||
|
row.append('td').html(runs[i].id);
|
||||||
|
row.append('td').html(runs[i].date);
|
||||||
|
row.append('td').html(runs[i].distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createTable();
|
||||||
|
|
||||||
|
d3.select('svg').on('click', (event) => {
|
||||||
|
const x = event.offsetX; //gets the x position of the mouse relative to the svg element
|
||||||
|
const y = event.offsetY; //gets the y position of the mouse relative to the svg element
|
||||||
|
|
||||||
|
const date = xScale.invert(x) //get a date value from the visual point that we clicked on
|
||||||
|
const distance = yScale.invert(y); //get a numeric distance value from the visual point that we clicked on
|
||||||
|
|
||||||
|
const newRun = { //create a new "run" object
|
||||||
|
id: ( runs.length > 0 ) ? runs[runs.length-1].id+1 : 1, //add this line
|
||||||
|
date: formatTime(date), //format the date object created above to a string
|
||||||
|
distance: distance //add the distance
|
||||||
|
}
|
||||||
|
runs.push(newRun); //push the new run onto the runs array
|
||||||
|
createTable(); //render the table
|
||||||
|
render(); //add this line
|
||||||
|
});
|
||||||
|
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="app.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<svg>
|
||||||
|
<g id="points"></g>
|
||||||
|
</svg>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>id</th>
|
||||||
|
<th>date</th>
|
||||||
|
<th>distance</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in new issue