Skip to content

Instantly share code, notes, and snippets.

@t3o-it
Last active June 9, 2017 11:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save t3o-it/338049fd8d6a648d805c71ebcb434ac6 to your computer and use it in GitHub Desktop.
Save t3o-it/338049fd8d6a648d805c71ebcb434ac6 to your computer and use it in GitHub Desktop.
Lazo Brush

d3-lazo-brush

<!DOCTYPE html>
<svg width="960" height="400"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="./pointinpolygon.js"></script>
<style>
path.lazo {
fill: #ddd;
stroke-width: 1px;
stroke: #ccc;
fill-opacity: 0.3;
}
svg:hover{
cursor:crosshair;
}
</style>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
margin = {top: 20, right: 30, bottom: 30, left: 40},
radius = 16,
xDomain = [-500, 500],
yDomain = [0, 100];
var color = d3.scaleOrdinal()
.range(d3.schemeCategory20);
var xScale = d3.scaleLinear()
.domain(xDomain)
.range([0, width - margin.left - margin.right]);
var yScale = d3.scaleLinear()
.domain(yDomain)
.range([height, 0]);
var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);
var chartContainer = svg
.attr('width', (width + margin.right + margin.left))
.attr('height', (height + margin.top + margin.bottom))
.append('g')
.attr('id', 'chartcontainer')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var xAxisEl = chartContainer.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis)
var yAxisEl = chartContainer.append('g')
.attr('class', 'y axis')
.call(yAxis);
var drawarea = chartContainer.append('g')
.attr('class', 'draw-area')
.attr('width', width)
.attr('height', height)
drawSamplePoints();
initLazoBrush();
function initLazoBrush() {
var lineFn = d3.line().curve(d3.curveBasisClosed);
var _kx = 0, _ky = 0;
var lazoMove = d3.drag()
.on("start", function (d, i, j) {
var _el = d3.select(j[i]).attr("txy").split(",");
_kx = d3.event.x;
_ky = d3.event.y;
})
.on("drag", function (d, i, j) {
var _x = d3.event.x - _kx;
var _y = d3.event.y - _ky;
_kx = d3.event.x;
_ky = d3.event.y;
console.log(_x, ' ', _y);
lazoPoints.forEach(function(_p){
_p[0] = _p[0] + _x;
_p[1] = _p[1] + _y;
})
drawPath();
drawarea.selectAll("circle")
.style("fill", function (d, i, j) {
return filter(d, i, lazoPoints);
})
})
var lazo = chartContainer.append("path")
.attr("class", "lazo")
.style("pointer-events", "all")
.call(lazoMove)
var lazoPoints = [];
var dragStart = function () {
lazoPoints = [];
lazo.attr("txy",[0,0])
.attr("transform", "translate(0,0)")
};
var drawPath = function () {
lazo.datum(lazoPoints)
.attr("d", lineFn);
};
var dragMove = function () {
lazoPoints.push([d3.event.x, d3.event.y]);
drawarea.selectAll("circle")
.style("fill", function (d, i, j) {
return filter(d, i, lazoPoints);
})
drawPath();
};
var dragEnd = function () {
//lazoPoints.push(lazoPoints[lazoPoints.length-1])
// lazoPoints.push(lazoPoints[0])
// drawPath();
};
var dragFn = d3.drag()
.on("start", dragStart)
.on("drag", dragMove)
.on("end", dragEnd);
svg.call(dragFn);
}
function filter(d, i, lazoPoints) {
return pointInPolygon([xScale(d.x), yScale(d.y)], lazoPoints) ? color(i) : "#efefef";
}
function drawSamplePoints() {
sampleData = d3.range(100).map(function () {
return {
x: Math.floor(Math.random() * (xDomain[1] - xDomain[0] - 40) + xDomain[0] + 40),
y: Math.floor(Math.random() * (yDomain[1] - yDomain[0] - 10) + yDomain[0] + 10)
};
});
drawarea.selectAll("circle")
.data(sampleData)
.enter().append("circle")
.attr("cx", function (d) {
return xScale(d.x);
})
.attr("cy", function (d) {
return yScale(d.y);
})
.attr("opacity", 0.8)
.style("pointer-events", "none")
.attr("r", radius)
.style("fill", function (d, i) {
return color(i);
})
.style("stroke", function (d, i) {
return color(i);
})
}
</script>
function pointInPolygon(point, vs) {
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
var x = point[0], y = point[1];
var inside = false;
for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
var xi = vs[i][0], yi = vs[i][1];
var xj = vs[j][0], yj = vs[j][1];
var intersect = ((yi > y) != (yj > y))
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment