function chart() {
let width = 600;
let height = 600;
let svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
svg.append('rect')
.attr('width', '100%')
.attr('height', '100%')
.attr('fill', '#0f172a');
let data = [
{
"__typename": "PropertyLocationProperty",
"lat": 34.191389,
"lon": -118.384772
},
{
"__typename": "PropertyLocationProperty",
"lat": 34.191389,
"lon": -118.384772
},
{
"__typename": "PropertyLocationProperty",
"lat": 34.168556,
"lon": -118.354664
}
]
let basePoint = {lat: 34.214946961868826, lon: -118.34711671528295};
let projection = d3.geoMercator()
.center([basePoint.lon, basePoint.lat])
.scale(1)
.translate([0, 0]);
// Compute the bounds of the data
let bounds = [projection([d3.min(data, d => d.lon), d3.min(data, d => d.lat)]), projection([d3.max(data, d => d.lon), d3.max(data, d => d.lat)])];
let dx = bounds[1][0] - bounds[0][0];
let dy = bounds[1][1] - bounds[0][1];
let x = (bounds[0][0] + bounds[1][0]) / 2;
let y = (bounds[0][1] + bounds[1][1]) / 2;
// Update scale and translation
let scale = 0.1 / Math.max(dx / width, dy / height);
let center = projection([basePoint.lon, basePoint.lat]);
let translate = [
width / 2 - center[0],
height / 2 - center[1]
];
projection = projection.scale(scale).translate(translate);
svg.append("circle")
.attr("cx", projection([basePoint.lon, basePoint.lat])[0])
.attr("cy", projection([basePoint.lon, basePoint.lat])[1])
.attr("r", 10)
.attr("fill", "#6366f1");
let maxDistance = 0;
data.forEach(point => {
let from = turf.point([basePoint.lon, basePoint.lat]);
let to = turf.point([point.lon, point.lat]);
let options = {units: 'miles'};
let angleDistance = d3.geoDistance([basePoint.lon, basePoint.lat], [point.lon, point.lat]);
let distance = angleDistance * 6371 * 0.621371; // convert from radians to miles (6371 is Earth's radius in kilometers, 0.621371 is km to miles conversion)
if (distance > maxDistance) maxDistance = distance;
// Draw dashed line
svg.append("line")
.attr("x1", projection([basePoint.lon, basePoint.lat])[0])
.attr("y1", projection([basePoint.lon, basePoint.lat])[1])
.attr("x2", projection([point.lon, point.lat])[0])
.attr("y2", projection([point.lon, point.lat])[1])
.attr("stroke", "white")
.attr("stroke-dasharray", "5,5");
// Draw orange dot for the data point
svg.append("circle")
.attr("cx", projection([point.lon, point.lat])[0])
.attr("cy", projection([point.lon, point.lat])[1])
.attr("r", 5)
.attr("fill", "#f97316");
// Display distance near the orange dot
let offset = 15; // To position the text a bit away from the dot
svg.append("text")
.attr("x", projection([point.lon, point.lat])[0] + offset)
.attr("y", projection([point.lon, point.lat])[1] + offset)
.attr("font-size", "12px")
.attr("text-anchor", "start")
.attr('fill', 'white')
.text(`${distance.toFixed(2)} miles`
).attr(
'font-family',
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
)
});
// Draw a circle around all the points with some padding
let padding = 10; // 10 miles padding
let radius = maxDistance + padding;
let circleRadius = projection([basePoint.lon + radius / 111.32, basePoint.lat])[0] - projection([basePoint.lon, basePoint.lat])[0]; // converting miles to degrees approx.
svg.append("circle")
.attr("cx", projection([basePoint.lon, basePoint.lat])[0])
.attr("cy", projection([basePoint.lon, basePoint.lat])[1])
.attr("r", circleRadius)
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-dasharray", "5,5");
return svg.node();
}