Reputation: 1521
In my code below I've set an intial zoom level after the page have loaded like this:
svg.transition().delay(500).duration(750)
.call(zooming.transform, transform)
function transform() {
return d3.zoomIdentity
.translate(-210, 0)
.scale(2);
}
The problem is that the x
value in the d3.zoomIdentity.translate(x, y)
is hardcoded.
What I want to know is if there's a way to set it so that it always zoom in to, let's say, the last six bars based on the data that's provided? (within reason)
Is using d3.zoomIdentity
the right way to go about it or is there some other method that would make it easier?
Here's my code:
const data = [
{name: "A", value: 67},
{name: "B", value: 92},
{name: "C", value: 82},
{name: "D", value: 53},
{name: "E", value: 20},
{name: "F", value: 88},
{name: "G", value: 15},
{name: "H", value: 94},
{name: "I", value: 66},
{name: "J", value: 53}
];
var svg = d3.select("#chart"),
margin = {top: 35, left: 35, bottom: 35, right: 35},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleBand()
.domain(data.map(d => d.name))
.range([margin.left, width - margin.right])
.padding(0.1)
var y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)]).nice()
.range([height - margin.bottom, margin.top])
var xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickSizeOuter(0))
svg.append("g")
.attr("class", "bars")
.attr("fill", "steelblue")
.selectAll("rect").data(data).enter().append("rect")
.attr("x", d => x(d.name))
.attr("y", d => y(d.value))
.attr("height", d => y(0) - y(d.value))
.attr("width", x.bandwidth());
svg.append("g")
.attr("class", "x-axis")
.call(xAxis);
svg.call(zoom);
function zoom(svg) {
const extent = [
[margin.left, margin.top],
[width - margin.right, height - margin.top]];
var zooming = d3.zoom()
.scaleExtent([1, 3])
.translateExtent(extent)
.extent(extent)
.on("zoom", zoomed)
svg.call(zooming);
svg.transition().delay(500).duration(750)
.call(zooming.transform, transform)
function transform() {
return d3.zoomIdentity
.translate(-210, 0)
.scale(2);
}
function zoomed() {
x.range([
margin.left, width - margin.right]
.map(d => d3.event.transform.applyX(d)));
svg.selectAll(".bars rect")
.attr("x", d => x(d.name))
.attr("width", x.bandwidth());
svg.selectAll(".x-axis").call(xAxis);
}
}
body {
margin: auto;
width: 850px;
}
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg id="chart" width="400" height="420"></svg>
Upvotes: 2
Views: 145
Reputation: 102218
If I understand your question correctly, you can get the last six bars by simply getting the x position of the sixth last:
-x(data[data.length - 6].name)
Since you're scaling by two, we have to multiply it accordingly:
-x(data[data.length - 6].name) * 2
Here is the code with that change:
const data = [
{name: "A", value: 67},
{name: "B", value: 92},
{name: "C", value: 82},
{name: "D", value: 53},
{name: "E", value: 20},
{name: "F", value: 88},
{name: "G", value: 15},
{name: "H", value: 94},
{name: "I", value: 66},
{name: "J", value: 53}
];
var svg = d3.select("#chart"),
margin = {top: 35, left: 35, bottom: 35, right: 35},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleBand()
.domain(data.map(d => d.name))
.range([margin.left, width - margin.right])
.padding(0.1)
var y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)]).nice()
.range([height - margin.bottom, margin.top])
var xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickSizeOuter(0))
svg.append("g")
.attr("class", "bars")
.attr("fill", "steelblue")
.selectAll("rect").data(data).enter().append("rect")
.attr("x", d => x(d.name))
.attr("y", d => y(d.value))
.attr("height", d => y(0) - y(d.value))
.attr("width", x.bandwidth());
svg.append("g")
.attr("class", "x-axis")
.call(xAxis);
svg.call(zoom);
function zoom(svg) {
const extent = [
[margin.left, margin.top],
[width - margin.right, height - margin.top]];
var zooming = d3.zoom()
.scaleExtent([1, 3])
.translateExtent(extent)
.extent(extent)
.on("zoom", zoomed)
svg.call(zooming);
svg.transition().delay(500).duration(750)
.call(zooming.transform, transform);
var xValue = -x(data[data.length - 6].name)*2;
function transform() {
return d3.zoomIdentity
.translate(xValue, 0)
.scale(2);
}
function zoomed() {
x.range([
margin.left, width - margin.right]
.map(d => d3.event.transform.applyX(d)));
svg.selectAll(".bars rect")
.attr("x", d => x(d.name))
.attr("width", x.bandwidth());
svg.selectAll(".x-axis").call(xAxis);
}
}
body {
margin: auto;
width: 850px;
}
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg id="chart" width="400" height="250"></svg>
Upvotes: 4