Published
Edited
Dec 13, 2021
Insert cell
Insert cell
state.selected
Insert cell
state.polygon
Insert cell
viewof state = {
const selection = d3.create("svg").attr("viewBox", [0, 0, width, height]),
svg = selection.node(),
path = d3.geoPath(),
l = selection.append("path").attr("class", "lasso"),
g = selection.append("g"),
points = g
.selectAll("circle")
.data(data)
.join("circle")
.attr("r", 1.5)
.attr("transform", d => `translate(${d})`);

selection.append("defs").append("style").text(`
.selected {r: 2.5; fill: red}
.lasso { fill-rule: evenodd; fill-opacity: 0.1; stroke-width: 1.5; stroke: #000; }
`);

function draw(polygon) {
l.datum({
type: "LineString",
coordinates: polygon
}).attr("d", path);

const selected = polygon.length > 2 ? [] : data;

// note: d3.polygonContains uses the even-odd rule
// which is reflected in the CSS for the lasso shape
points.classed(
"selected",
polygon.length > 2
? d => d3.polygonContains(polygon, d) && selected.push(d)
: false
);

svg.value = { polygon, selected };
svg.dispatchEvent(new CustomEvent('input'));
}

selection.call(lasso().on("start lasso end", draw));
draw(defaultLasso);

return svg;
}
Insert cell
function lasso() {
const dispatch = d3.dispatch("start", "lasso", "end");
const lasso = function(selection) {
const node = selection.node();
const polygon = [];

selection
.on("touchmove", e => e.preventDefault()) // prevent scrolling
.on("pointerdown", e => {
trackPointer(e, {
start: p => {
polygon.length = 0;
dispatch.call("start", node, polygon);
},
move: p => {
polygon.push(p.point);
dispatch.call("lasso", node, polygon);
},
end: p => {
dispatch.call("end", node, polygon);
}
});
});
};
lasso.on = function(type, _) {
return _ ? (dispatch.on(...arguments), lasso) : dispatch.on(...arguments);
};

return lasso;
}
Insert cell
Insert cell
data = {
const rngx = d3.randomNormal(width / 2, Math.min(width, height) / 3),
rngy = d3.randomNormal(height / 2, Math.min(width, height) / 3);
return Array.from({ length: 500 }, () => [rngx(), rngy()]);
}
Insert cell
height = Math.min(500, width * 0.7)
Insert cell
import { trackPointer } from "@fil/pointer-events"
Insert cell
d3 = require("d3@5", "d3-selection@2.0.0-rc.2")
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