function draw_map_canvas_stroke(
geojson,
size = 600,
stroke_number = 8,
opacity_gradient = false,
stroke_gradient = false,
colour_scale = false,
filled = false,
colour = "teal",
stroke_thickness_const = 1,
ripple_extent = 40,
curve_this = d3.curveCatmullRomClosed,
start = 2,
stroke_gradient_values = [1, 3],
spacing_exponent = 1 / 2
) {
let projection_canvas = d3
.geoMercator()
.fitSize([size - ripple_extent, size - ripple_extent], geojson);
let projection_translate = projection_canvas.translate();
projection_canvas = projection_canvas.translate([
projection_translate[0] + ripple_extent / 2,
projection_translate[1] + ripple_extent / 2
]);
function curveContext(curve) {
return {
moveTo(x, y) {
curve.lineStart();
curve.point(x, y);
},
lineTo(x, y) {
curve.point(x, y);
},
closePath() {
curve.lineEnd();
}
};
}
function geoCurvePath(curve, projection, context) {
return object => {
const pathContext = context === undefined ? d3.path() : context;
d3.geoPath(projection_canvas, curveContext(curve(pathContext)))(object);
return context === undefined ? pathContext + "" : undefined;
};
}
const context = DOM.context2d(size, size);
const path_svg = geoCurvePath(curve_this)(geojson);
let path = new Path2D(path_svg);
const path_orig = d3.geoPath(projection_canvas, context);
const opacity = d3
.scalePow()
.exponent(0.8)
.domain([0, stroke_number])
.range([0, 1]);
const stroke_width = d3
.scalePow()
.exponent(spacing_exponent)
.domain([0, stroke_number])
.range([ripple_extent, start]);
const stroke_thickness = d3
.scalePow()
.exponent(3)
.domain([0, stroke_number])
.range(stroke_gradient_values);
for (let i = 0; i <= stroke_number; i++) {
context.beginPath();
context.strokeStyle = colour_scale
? d3.interpolateSpectral(1 - i / stroke_number)
: colour;
context.globalAlpha = opacity_gradient ? opacity(i) : 1;
context.lineWidth = stroke_gradient
? stroke_width(i) + stroke_thickness(i)
: stroke_width(i) + stroke_thickness_const;
context.stroke(path);
if (!filled) {
context.globalAlpha = 1;
context.beginPath();
context.lineWidth = stroke_width(i);
context.globalCompositeOperation = 'destination-out';
context.stroke(path);
context.globalCompositeOperation = 'source-over';
}
}
context.beginPath();
path_orig(geojson);
context.lineWidth = 2;
context.fillStyle = colour;
context.fill();
return context.canvas;
}