function mapView({
features,
container,
render,
projection,
options,
dispatch
}) {
if (container === undefined) container = DOM.context2d(width, height).canvas;
if (features === undefined)
features = {
type: "FeatureCollection",
features: []
};
if (render === undefined)
render = defaultRenderer;
const w = parseInt(container.style.width) || container.width,
h = (w * container.height) / container.width,
elements = features.features,
svg = d3.create("svg");
const path = d3.geoPath(projection);
const wrapper = html`<div style="position:relative">
${svg.node()}
${container}
`;
svg
.style("position", "absolute")
.style("top", "0")
.style("z-index", 2)
.attr("viewBox", `0 0 ${w} ${h}`);
const gGraticule = svg
.append("path")
.attr("id", "graticule")
.style("fill", "none")
.style("stroke", "yellow")
.datum(d3.geoGraticule10());
const gPaths = svg.append("g").attr("id", "paths");
const gHandles = svg.append("g").attr("id", "handles");
function updateSvg() {
gPaths
.selectAll("path")
.data(elements)
.join("path")
.attr("d", path)
.style("stroke", d => d.properties.color)
.style("fill", d => d.properties.color)
.style("fill-opacity", d =>
["Point", "MultiPoint", "Polygon", "MultiPolygon"].includes(
d.geometry.type
)
? 0.4
: 0
)
.on("click", d => {
const sourceEvent = d3.event;
if (sourceEvent && sourceEvent.shiftKey) {
// multiple select
} else {
elements.forEach(d => delete d.selected);
}
d.selected = true;
dispatch.call("data", null, "selection");
});
const symbol = d3.symbol().size(40)();
gHandles
.selectAll("path")
.data(geoPoints(features.features, projection))
.join("path")
.attr("d", symbol)
.attr("transform", d => `translate(${d.xy})`)
.attr("opacity", 1)
.attr("fill", d => (d.elt.selected && !d.midpoint ? "black" : "none"))
.attr("stroke", "black");
}
svg
.on("click", d => {})
.call(
drag(elements, projection).on(
"start.render drag.render end.render",
() => {
// render(container, features, projection);
updateSvg();
dispatch.call("data", null, "drag");
}
)
);
let zoom,
transform = d3.zoomIdentity;
if (options.zoom) {
transform.x = projection.translate()[0];
transform.y = projection.translate()[1];
transform.k = projection.scale();
zoom = d3.zoom().on("zoom", () => {
transform = d3.event.transform;
projection.translate([transform.x, transform.y]).scale(transform.k);
render(container, features, projection);
updateSvg();
});
svg.call(zoom).call(zoom.transform, transform);
}
dispatch.on("update.map", () => {
wrapper.value = features;
render(container, features, projection);
updateSvg();
wrapper.dispatchEvent(new CustomEvent("input"));
});
dispatch.on(
"zoomTo",
debounce(d => {
if (zoom) {
const { x, y, k } = transform;
projection.fitExtent(
[
[width * 0.2, height * 0.2],
[width * (1 - 0.2), height * (1 - 0.2)]
],
d
);
transform.x = projection.translate()[0];
transform.y = projection.translate()[1];
transform.k = projection.scale();
// todo: the transition doesn't work
projection.translate([x, y]).scale(k);
svg
.transition()
.duration(750)
.call(zoom.transform, transform);
}
}, 400)
);
wrapper.value = features;
return wrapper;
}