Public
Edited
Sep 27, 2023
2 forks
Importers
47 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
sketch(world, {
fill: "none",

paper: true,
k: k,
stroke: stroke,
strokeWidth1: strokewidth1,
strokeWidth2: strokewidth2
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
sketch(world, {
paper: true,
k: 0.05,
stroke: "none",
fill: fill,
overflow: overflow,
roughness: roughness,
hachureGap: hachureGap,
fillWeight: fillWeight,
fillStyle: fillStyle,
bowing: bowing
})
Insert cell
Insert cell
Insert cell
Insert cell
sketch(world, {
fill: "none",
paper: true,
k: k2,
title: projection.name + " projection",
projection: projection.proj,
stroke: "#000"
})
Insert cell
Insert cell
viewof geom = html`<input type=file>`
Insert cell
sketch(geom, {
fill: "none",
paper: true
})
Insert cell
Insert cell
function sketch(
geojson,
{
// GLOBAL PARAMETERS
title,
title_size = 32,
title_fill = "#333333",
paper = true, // paper background
width = 700, // width of the map
margin = 10, // margin
projection = d3.geoIdentity().reflectY(true),
k = 0.1, // level of simplification
// FILL
fill = "#346E9C", // fill color
fillOpacity = 1, // fill opacity
fillWeight = 0.5, // fill weight
fillStyle = "zigzag", // fill style: hachure, solid, zigzag, cross-hatch, dots, dashed, or zigzag-line
hachureGap = 2.5, // hachure gap
roughness = 8, // roughness
bowing = 0, // bowing
overflow = true, // coloring overflow (boolean)
// STROKE (2 overlapping lines)
stroke = "#000", // stroke color
strokeWidth1 = 1, // strokeWidth of the 1st line
strokeWidth2 = 0.5, // strokeWidth of the 2nd line
baseFrequency1 = 0.03, // baseFrequency (feTurbulence) of the 1st line
baseFrequency2 = 0.06, // baseFrequency (feTurbulence) of the 2nd line
scale1 = 5, // scale (feDisplacementMap) of the 1st line
scale2 = 7 // scale (feDisplacementMap) of the 2ndline
} = {}
) {
// simplify and merge
let land = geo.simplify(geojson, { k: k, merge: true });

let delta = title ? 55 : 0;
let adjust = paper ? [width / 12, 10, 20] : [0, 0, 0];
const [[x0, y0], [x1, y1]] = d3
.geoPath(projection.fitWidth(width - adjust[0] - margin * 2, land))
.bounds(land);
let trans = projection.translate();
projection.translate([
trans[0] + adjust[0] + margin,
trans[1] + adjust[1] + margin + delta
]);
let height = Math.ceil(y1 - y0) + adjust[2] + margin * 2 + delta;

// start svg
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("width", width)
.style("height", height)
.style("background", "white");

if (paper) {
svg
.append("g")
.append("image")
.attr("xlink:href", background)
.attr("width", width)
.attr("x", 0)
.attr("y", 0);
}

// rough
const rc = rough.svg(svg.node());

// svg filters (stroke)
let defs = svg.append("defs");
const pencil1 = defs.append("filter").attr("id", "pencil1");
pencil1.append("feTurbulence").attr("baseFrequency", baseFrequency1);
pencil1
.append("feDisplacementMap")
.attr("in", "SourceGraphic")
.attr("scale", scale1);
const pencil2 = defs.append("filter").attr("id", "pencil2");
pencil2.append("feTurbulence").attr("baseFrequency", baseFrequency2);
pencil2
.append("feDisplacementMap")
.attr("in", "SourceGraphic")
.attr("scale", scale2);

// contour smoothing
const path = smooth(d3.curveBasisClosed, projection);

// land clip (for clipping)
svg
.append("clipPath")
.attr("id", `myclip`)
.append("path")
.datum(land)
.attr("d", path);

// background pattern (fill)
svg
.append("g")
.attr("opacity", fillOpacity)
.attr("clip-path", overflow == true ? `none` : `url(#myclip)`)
.node()
.append(
rc.path(path(land.features[0]), {
stroke: "none",
bowing: bowing,
fill: fill,
fillWeight: fillWeight,
hachureGap: hachureGap,
roughness: roughness,
fillStyle: fillStyle
})
);

// contour patern (stroke)
svg
.append("path")
.datum(land)
.attr("d", path)
.attr("fill", "none")
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth1)
.attr("filter", "url(#pencil1)");
svg
.append("path")
.datum(land)
.attr("d", path)
.attr("fill", "none")
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth2)
.attr("filter", "url(#pencil2)");

// Title

svg
.append("text")
.attr("x", width / 2)
.attr("y", 45)
.attr("text-anchor", "middle")
.style("font-family", "Permanent Marker")
.attr("font-size", title_size)
.attr("fill", title_fill)
.text(title);

return svg.node();
}
Insert cell
Insert cell
style = html`<style>
@import url('https://fonts.googleapis.com/css2?family=Permanent+Marker&display=swap');
</style>`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
//rough = require("roughjs@4").catch(() => window.rough)
Insert cell
rough = (await import("https://cdn.skypack.dev/roughjs")).default
Insert cell
Insert cell
Insert cell
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