Public
Edited
Nov 29, 2023
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require('d3@7')
Insert cell
Insert cell
parkData = FileAttachment("parklocations.csv").csv().then(data => {
return data.map(d => ({
park: d.PARK,
latitude: +d.LATITUDE,
longitude: +d.LONGITUDE,
state: d.STATE
}));
});
Insert cell
Insert cell
plotVars = (
{visualWidth: 1000,
visualHeight: 618,
margin: 25,
}
);
Insert cell
Insert cell
Insert cell
createVisualization('national-parks')
Insert cell
// this function sets up the visualization
async function createVisualization(targetDiv) {
let visual = d3.create('svg')
.attr('width', plotVars.visualWidth)
.attr('height', plotVars.visualHeight)
.style('background-color', 'white');

visual.append('image')
.attr('width', plotVars.visualWidth - 2 * plotVars.margin)
.attr('height', plotVars.visualHeight - 2 * plotVars.margin)
.attr('transform', `translate(${plotVars.margin},${plotVars.margin})`)
.attr('xlink:href', await FileAttachment("US MAP.png").url());

createCircle(visual);
plotParks(visual);

document.getElementById('circleSlider').value = '150'; // reset slider
document.getElementById('national-parks').innerHTML = ''; // delete previous visualization
document.getElementById(targetDiv).appendChild(visual.node()); // append new visualization
}
Insert cell
Insert cell
function projectX(longitude) {
const scale = 16.5211515391;
const translateX = 2129.89227018;
const projectedX = longitude * scale + translateX;
return projectedX;
}
Insert cell
function projectY(latitude) {
const scale = -20.8431819159;
const translateY = 1086.30521294;
const projectedY = latitude * scale + translateY;
return projectedY;
}
Insert cell
Insert cell
// this function handles the code for plotting the parks and the associated mouseover events
async function plotParks(visual) {

visual.selectAll('.parks')
.data(parkData, d=>d.park)
.join('image')
.attr('r', 2)
.attr('class', 'parks')
.style('fill', 'gray')
.attr('width', 18)
.attr('height', 18)
.attr('xlink:href', await FileAttachment('unselectedtree.png').url())
.attr('x',
d => {
var projectedX = projectX(d.longitude);
return projectedX;
})
.attr('y',
d => {
var projectedY = projectY(d.latitude);
return projectedY;
})
// mouseover events
.on('mouseover', async function (event, d) {

var projectedLocation = [projectX(d.longitude), projectY(d.latitude)];

d3.select(this).attr('xlink:href', await FileAttachment('selectedtree.png').url())
visual.append('text')
.attr('class', 'parkLabel')
.attr('x', projectedLocation[0] - 10)
.attr('y', projectedLocation[1] - 10)
.text(d.park)
})
.on('mouseout', async function(event, d) {
visual.selectAll('.parkLabel').remove()
d3.select(this).attr('xlink:href', await FileAttachment('unselectedtree.png').url())
})
}
Insert cell
Insert cell
// this function creates the draggable circle
function createCircle(visual) {

// creating circle
const circle1 = visual.append('circle') // create blue circle
.join('circle')
.attr('cx', 500)
.attr('cy', 325)
.attr('r', 150)
.style('fill', 'yellowgreen')
.attr('opacity', 0.50)
.attr('id', 'circle1')
.attr('class', 'draggable');

// dragging

let isDragging = false;

visual.selectAll('.draggable').call(d3.drag()
.on('start', function() {
isDragging = true;
d3.select(this).attr('stroke', 'forestgreen') // change stroke to orange when dragging
d3.select(this).attr('stroke-width', '3');
})
.on('drag', function(event) {
if (isDragging) {
d3.select(this)
.attr('cx', event.x)
.attr('cy', event.y);
}
})
.on('end', function() {
isDragging = false;
d3.select(this).attr('stroke', null);
}));

// resizing

d3.select('#circleSlider')
.on('input', function() {
let newRadius = this.value; // get the value of the slider
d3.select('#circle1')
.attr('r', newRadius); // update radius
});
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more