刷子&缩放(Brush & Zoom)
源码: https://github.com/HK-Kevin/d...
demo:https://hk-kevin.github.io/d3...
原理:
brush
事件控制zoom
的放缩.
源码分析:
let svg = d3.select("svg"),
margin = {top :20,right:20,bottom:50,left:50},
areaWidth = svg.attr("width") - margin.left-margin.right,
areaHeight = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g")
.attr("transform",`translate(${margin.left},${margin.top})`)
.attr("width",areaWidth)
.attr("height",areaHeight)
let xScale =d3.scaleLinear()
.domain([0,22])
.range([0,areaWidth]);
let yScale = d3.scaleLinear()
.domain([40,0])
.range([0,areaHeight]) ;
let xAxis = d3.axisBottom(xScale) ;
let yAxis = d3.axisLeft(yScale) ;
let line = d3.line()
.curve(d3.curveStepAfter)
.x(function(d){
return xScale(d.x)
})
.y(function (d) {
return yScale(d.y)
});
let t =d3.transition()
.duration(500)
.ease(d3.easeLinear)
let xGrooup = g.append("g")
.attr("transform",`translate(0,${areaHeight})`)
.call(xAxis)
let yGroup = g.append("g")
.attr("transform",`translate(0,0)`)
.call(yAxis)
g.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", areaWidth)
.attr("height", areaHeight);
let updateLine = g.append("g")
.attr("class","chart")
.selectAll("line")
.data(data)
let enterLine = updateLine.enter();
let exitLine = updateLine.exit();
let path = enterLine.append("path")
.attr("clip-path", "url(#clip)")
.attr("class","line")
.attr("d",line)
.attr("fill","none")
.attr("stroke",0)
.transition(t)
.attr("stroke-width",2)
.attr("stroke","green")
exitLine.remove();
let zoom = d3.zoom()
.scaleExtent([1, 8])
.translateExtent([[0,0], [areaWidth, areaHeight]])
.on("zoom", zoomed);
let zoomRect = svg.append("rect")
.attr("width",areaWidth)
.attr("height",areaHeight)
.attr("fill","none")
.attr("pointer-events","all")
.call(zoom);
let brush = d3.brushX()
.extent([[0, 0], [areaWidth, 20]])
.on("brush end", brushed);
let xBrush = d3.scaleLinear().range([0, areaWidth])
.domain(xScale.domain());
let xTop = d3.axisTop(xBrush);
let brushBox = svg.append("g")
.attr("transform",`translate(${margin.left},${margin.top})`)
.attr("class", "brushBox");
brushBox.append('g')
.attr('fill','black')
.call(xTop);
brushBox.append("g")
.attr("class", "brush")
.attr("fill", 'red')
.call(brush)
.call(brush.move, xScale.range())
.selectAll("rect")
.attr("width", areaWidth)
.attr("height", 20);
function zoomed() {
let t = d3.event.transform.rescaleX(xScale)
xGrooup.call(xAxis.scale(t))
g.select("path.line").attr("d", line.x(function(d){
return t(d.x)}))
brushBox.select(".brush").call(brush.move,xScale.range().map(d3.event.transform.invertX,d3.event.transform))
}
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
let s = d3.event.selection || xScale.range();
xScale.domain(s.map(xBrush.invert, xBrush));
zoomRect .call(zoom.transform, d3.zoomIdentity.scale(areaWidth / (s[1] - s[0]))
.translate(-s[0], 0))
}