Public
Edited
May 30, 2024
Importers
Insert cell
Insert cell
viewof minArea = Range([0.001, 0.01], { step: 0.001 })
Insert cell
ukPath = path(mainlandUkCoords)
Insert cell
chart = {
const svg = d3.select(DOM.svg(w, h))

var path = smooth(d3.curveBasisClosed, projection);

svg.append('path')
.datum(mainlandUkCoords)
.attr('d', path)
.attr("id","ukPath")
// Styling
.style('fill', 'white')
.style('stroke', 'lightgrey');

svg.append("circle")
.attr("cx", projection(coords)[0])
.attr("cy", d => projection(coords)[1])
.attr("r", 3)
.attr("fill", "black")


return svg.node()
}
Insert cell
Insert cell
w=400
Insert cell
h=400
Insert cell
Insert cell
path = smooth(d3.curveBasisClosed, projection)
Insert cell
projection = d3.geoMercator()
.fitSize([w, h], mainlandUkCoords)
Insert cell
coords = [0.0662760584905233, 51.656221558916265]
Insert cell
mainlandUkCoords
Insert cell
Insert cell
Insert cell
Insert cell
engWales_simplified = {
let engWales_simplified = topojson.presimplify(engwalestopo);
let min_weight = topojson.quantile(engWales_simplified, minArea);
engWales_simplified = topojson.simplify(engWales_simplified, min_weight);
return topojson.merge(engWales_simplified, Object.values(engWales_simplified.objects))
}
Insert cell
Insert cell
Insert cell
require("https://unpkg.com/svg-path-parser@1.1.0/parser.js")
Insert cell
import { Range } from "@observablehq/inputs"
Insert cell
import {engwalestopo} from "77788580325615c3"
Insert cell
import { geoCurvePath as smooth } from "@d3/context-to-curve"
Insert cell
topojson = require("https://unpkg.com/topojson@3")
Insert cell
Insert cell
Insert cell
randPoints = engWales_simplified.coordinates[2][0].map(function(d){
return [d[0]*(1-(Math.random()+0.3)/300), d[1]*(1-(Math.random()+0.3)/300)]
// return [Math.random(), d[1]]
})
Insert cell
Insert cell
Insert cell
Insert cell
svgDims(fishSVG)
Insert cell
fishDims = svgDims(fishSVG)
Insert cell
Insert cell
svgDims = function(svg){

// Add the SVG element to the DOM so we can determine its size.
document.body.appendChild(svg);

// Computing the bounding box of the content.
const box = svg.querySelector("[name=content]").getBBox();

// Remove the SVG element from the DOM.
svg.remove();

return {x: box.x, y: box.y, w: box.width, h:box.height}

}
Insert cell
ukDims = svgDims(ukSVG)
Insert cell
fishCentroid = {
return [fishDims.x + (fishDims.w / 2), fishDims.y + (fishDims.h / 2)]
}
Insert cell
ukCentroid = {
return [ukDims.x + (ukDims.w / 2), ukDims.y + (ukDims.h / 2)]
}
Insert cell
Insert cell
fishCentroidTranslation2 = [(width/2) - fishCentroid[0], (height/2) - fishCentroid[1]]
Insert cell
height=400
Insert cell
fishDims.w
Insert cell
fishPathAbs
Insert cell
Insert cell
fishPathAbs
Insert cell
fishPath2 = {
// var regex = /([Mm])\s*(-?\d+(\.\d+)?)\s*,\s*(-?\d+(\.\d+)?)/g;
// var regex = /([MmLlCc])\s*(-?\d+(\.\d+)?)\s*,\s*(-?\d+(\.\d+)?)/g;
// var regex = /([MmLlCc])\s*(-?\d+(\.\d+)?)\s*,\s*(-?\d+(\.\d+)?)\s*,\s*(-?\d+(\.\d+)?)\s*,\s*(-?\d+(\.\d+)?)/g;
var regex = /[MLCZmlcz][^MLCZ]*/g;


// return fishPathAbs.match(regex)

function replaceFn(match, command, x, _, y){
console.log([match, command, x, _, y])
var newX = parseFloat(x) + fishCentroidTranslation[0];
var newY = parseFloat(y) + fishCentroidTranslation[1];

return command + ' ' + newX + ',' + newY;
}

var shiftedPathString = fishPathAbs.replace(regex, replaceFn);

return shiftedPathString;
}
Insert cell
bboxScales = {
const ukArea = ukDims.w * ukDims.h;
const fishArea = fishDims.w * fishDims.h;
const aspectRatio = fishDims.w / fishDims.h;
const newFishWidth = Math.sqrt(ukArea * aspectRatio);
const newFishHeight = newFishWidth / aspectRatio;
const newFishArea = newFishWidth * newFishHeight
const scaleX = newFishWidth / fishDims.w;
const scaleY = newFishHeight / fishDims.h;
return {scaleX, scaleY}
}
Insert cell
Insert cell
adjustedFishPath
Insert cell
{
const width=1500, height=400;
const svg = d3.select(DOM.svg(width, height))
const initialPath = svg.append("path")
.attr("d", adjustedFishPath)
// .attr("transform", "translate(50, 50)")
.attr("stroke", "blue")
.attr("fill", "none")

svg.append("circle")
.attr("cx", fishCentroid[0])
.attr("cy", fishCentroid[1])
.attr("r", 3)
.attr("fill", "red")

svg.append("circle")
.attr("cx", ukCentroid[0])
.attr("cy", ukCentroid[1])
.attr("r", 3)
.attr("fill", "green")

// Define a custom easing function (e.g., quadraticInOut)
const customEasing = d3.easeCubicIn;
// Transition between the two paths using Flubber
initialPath.transition().ease(customEasing)
.duration(3500) // Transition duration in milliseconds
.attrTween("d", function () {
const interpolator = flubber.interpolate(adjustedFishPath, ukPath);
return function (t) {
return interpolator(t);
};
});

return svg.node()
}
Insert cell
flubber = require("flubber@0.4")
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