how to use zoom.wheelDelta in d3 v4 - d3.js

I do not know why wheelDelta not working . it says wheeldelta is not a function. I want to control zooming level on scroll up and down of mouse wheel. if I can defined delta value then I can define how much zoom will happen on a single tick rotation of scroll. the default behavior is too fast. I am using this reference
https://github.com/d3/d3-zoom/blob/master/README.md#_zoom
svg = d3.select("#treeSection").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.call(d3.zoom()
.wheelDelta([2])
.scaleExtent([1 / 2, 4])
.on("zoom", zoomed));
g = svg.append("g")
.attr("transform", "translate(" +
margin.left + "," + margin.top + ")");
function zoomed() {
g.attr("transform", d3.event.transform);
}

Define the wheelDelta function
Make a wheel delta function
function myDelta() {
return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1) / 1500;
}
You may increase the constant 1500 to any number of your choice for regulating the delta.
Now in zoom define the wheelDelta like this:
var zoom = d3.zoom()
.scaleExtent([1, 32])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.wheelDelta(myDelta)//your function
.on("zoom", zoomed);
Reference here
Working code here

Related

Not able add zoom/pan on scatter plot

I created a scatter plot using D3.js.I would like to add the functionality to zoom and pan.
I have declare zoom behaviour for scatter plot.Try to use it in svg element.
But it throws error says argument of type zoom behavior is not assignable to parameter of type selection:selection SVGElement
I am just a beginner with using D3.Can anyone help or have any suggestions?
var zoom = d3.zoom()
.scaleExtent([0.3, 2])
.on("zoom", function () {
svg.attr("transform", d3.event.transform)
});
var svg = d3.select(component).append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
Welcome to Stack Overflow.
You need to provide a function to the onzoom handler
.on("zoom", function () {
svg.attr("transform", d3.event.transform)
});
should look more like this, where you are calling your own function and passing it the transform as a parameter
d3.select(context.canvas).call(d3.zoom()
.scaleExtent([1, 8])
.on("zoom", () => zoomed(d3.event.transform)));
The zoomed function could be this:
function zoomed(transform) {
context.save();
context.clearRect(0, 0, width, height);
context.translate(transform.x, transform.y);
context.scale(transform.k, transform.k);
context.beginPath();
for (const [x, y] of data) {
context.moveTo(x + r, y);
context.arc(x, y, r, 0, 2 * Math.PI);
}
context.fill();
context.restore();
}
These snippets were taken from this example:
https://observablehq.com/#d3/zoom-canvas

Updating zoom behavior from v3 to v5

The problem i am facing is that i am not able to write the function following in my code because of version mismatch.
Code is
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
I have tried by this way
const zoom = d3.zoom()
.scaleExtent([1, 4])
.x(this.xScale)
.on('zoom', () => {})
But it does not work for me.
How to write same function in d3 version 5? I want to make line chart scrollable in x axis with y axis as fixed position using d3 version 5
This is my implementation Basic Code
private createLineChart() {
this.width = 2000 - this.margin.left - this.margin.right;
this.height = 600 - this.margin.top - this.margin.bottom;
// X AXIS
this.xScale = d3.scaleBand()
.domain(this.dataset[0].fluencyData.map((data) => {
return new Date(data.date);
}))
.range([0, this.width]);
// Y AXIS
this.yScale = d3.scaleLinear()
.domain([0, 110])
.range([this.height, 0]);
// Line Generator
this.line = d3.line()
.x((data) => this.xScale(new Date(data.date)))
.y((data) => this.yScale(data.wcpm));
// .curve(d3.curveMonotoneX);
// Add SVG to Div
this.svg = d3.select('#displayChart').append('svg')
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr(
'viewBox',
'0 0 ' +
(this.width + this.margin.left + this.margin.right) +
' ' +
(this.height + this.margin.top + this.margin.bottom))
// .attr('width', this.width + this.margin.left + this.margin.right)
// .attr('height', this.height + this.margin.top + this.margin.bottom)
.append('g')
.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
// Define the div for the tooltip
this.toolTipDiv = d3.select('#displayChart').append('div')
.attr('class', 'tooltip')
.style('opacity', 0);
// Append XAXIS to the SVG
this.svg.append('g')
.attr('class', 'xAxis')
.attr('transform', 'translate(0,' + this.height + ')')
.call(d3.axisBottom(this.xScale).tickSizeOuter(0).tickFormat(d3.timeFormat('%b %d')));
const zoom = d3.zoom()
.scaleExtent([1, 4])
.extent([100, 100], [this.width - 100, this.height - 100])
.x(this.xScale)
.on('zoom', () => {
console.log(d3.event.transform);
// this.svg.select('#displayChart').attr('d', this.line);
});
this.svg.call(zoom);
// Append YAXIS to SVG
this.svg.append('g')
.attr('class', 'yAxis')
.call(d3.axisLeft(this.yScale).tickSize(-this.width)
);
// Make a Path for Dataset
this.svg.append('path')
.datum(this.dataset[0].fluencyData)
.attr('class', 'line')
.attr('d', this.line)
.attr('transform', 'translate(' + this.margin.left + ',0)');
// Text Heading of DATE in chart
this.svg.append('text')
.attr('transform', 'translate(' + (-20) + ',' + (this.height + 13) + ')')
.attr('dy', '.35em')
.attr('class', ' xAxis')
.text('Date');
}
}
Error I am getting is
LineChartComponent_Host.ngfactory.js? [sm]:1 ERROR TypeError: d3__WEBPACK_IMPORTED_MODULE_2__.zoom(...).scaleExtent(...).x is not a function
at LineChartComponent.push../src/app/line-chart/line-chart.component.ts
With d3v3 and before, the zoom could track a scale's state. From the documentation, scale.x(): "Specifies an x-scale whose domain should be automatically adjusted when zooming." (docs). This modifies the original scale.
D3v4+ does not have zoom.x or zoom.y methods.
With d3v4+, the zoom does not track or modifiy a d3 scale's state. Infact, for d3v4+, the zoom behavior doesn't even track the current zoom state: "Zoom behaviors no longer store the active zoom transform (i.e., the visible region; the scale and translate) internally. The zoom transform is now stored on any elements to which the zoom behavior has been applied.(change log)".
As part of this, and more importantly, "Zoom behaviors are no longer dependent on scales, but you can use transform.rescaleX, transform.rescaleY, transform.invertX or transform.invertY to transform a scale’s domain(change log)".
So rather than have the zoom update the d3 scale, we need to do this ourselves. The most common way this is done is through a reference scale, which remains unchanged, and a scale to which we apply the zoom transform:
var zoom = d3.zoom()
.on("zoom",zoomed)
var x = d3.scaleLinear().... // working scale
var x2 = x.copy(); // reference scale.
function zoomed() {
x = d3.event.transform.rescaleX(x2) // update the working scale.
// do something...
}
So, something like this:
var x = d3.scale.linear()
.domain([0,1])
.range([0,500]);
var zoom = d3.behavior.zoom()
.x(x)
.scaleExtent([1, 10])
.on("zoom", zoomed);
var svg = d3.select("svg")
.call(zoom);
var axis = d3.svg.axis()
.orient("bottom")
.scale(x);
var axisG = svg.append("g")
.attr("transform", "translate(0,30)")
.call(axis);
function zoomed() {
axisG.call(axis);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<svg width="500" height="200"></svg>
Becomes something like that:
var x = d3.scaleLinear()
.domain([0,1])
.range([0,500]);
var x2 = x.copy(); // reference.
var zoom = d3.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
var svg = d3.select("svg")
.call(zoom);
var axis = d3.axisBottom().scale(x)
var axisG = svg.append("g")
.attr("transform", "translate(0,30)")
.call(axis);
function zoomed() {
x = d3.event.transform.rescaleX(x2)
axis.scale(x);
axisG.call(axis);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="500" height="200"></svg>
Note that d3.event.transform.rescaleX is for continuous scales - you have an ordinal band scale, so we'll need to use a slightly modified approach for band and/or point scales:
var x = d3.scaleBand()
.domain(d3.range(10).map(function(d) { return d/10; }))
.range([0,500]);
var x2 = x.copy(); // reference.
var zoom = d3.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
var svg = d3.select("svg")
.call(zoom);
var axis = d3.axisBottom().scale(x)
var axisG = svg.append("g")
.attr("transform", "translate(0,30)")
.call(axis);
function zoomed() {
// Rescale the range of x using the reference range of x2.
x.range(x2.range().map(function(d) {
return d3.event.transform.applyX(d);
}))
axisG.call(axis);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="500" height="200"></svg>
This is band/point scale solution is based on this issue and Bostock's proposed solution to it

Add Zoom to a Grouped Bar Chart that uses a scaleBand

I'm trying to use rescaleX on a scaleBand to add zoom functionality to a Grouped Bar Chart.
var x0 = d3.scaleBand()
.rangeRound([0, width])
.paddingInner(0.1);
var x1 = d3.scaleBand()
.padding(0.05);
var zoom = d3.zoom()
.scaleExtent([1, 8])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", () => { zoomed() });
...
function zoomed() {
var t = d3.event.transform;
var x0t = t.rescaleX(this.x0);
var x1t = t.rescaleX(this.x1);
...
}
But t.rescaleX(this.x0) doesn't work on a scaleBand, how can I apply zoom functionallity to a scaleBand?
Here is a full codepen Grouped Bar Chart
I was able to achieve this by changing the zoomed function to:
function zoomed() {
var t = d3.event.transform;
// redefine the x0 domain range with the event transform scale (k)
x0.range([0, width * t.k]);
// transform .barGroup using redefined domain range and event transform params
g.selectAll(".barGroup")
.attr("transform", function(d) { return "translate(" + (x0(d.State) + t.x) + ",0)scale(" + t.k + ",1)"; });
// apply transform to .axis--x and call xAxis
g.select(".axis--x")
.attr("transform", "translate(" + t.x + "," + (height) + ")")
.call(xAxis);
}
Full codepen here
Update:
A better method of zooming a scaleBand bar chart by Mike Bostock (non-grouped)
https://beta.observablehq.com/#mbostock/d3-zoomable-bar-chart
Update 2:
Updated Grouped bar chart zoom function:
function zoomed() {
x0.range([0, width].map(d => d3.event.transform.applyX(d)));
x1.rangeRound([0, x0.bandwidth()]);
g.selectAll(".barGroup").attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
g.selectAll(".bar").attr("x", function(d) { return x1(d.key); }).attr("width", x1.bandwidth());
g.select(".axis--x").call(xAxis);
}
Full Codepen: here

How to zoom to d3.js svg overlay on google map

I have a d3.js svg which I overlaid on Google map using OverlayView. Then a user specifies a zip code in an input text, and I need for my map to zoom in to that particular zip code. I have a latitude and longitude for the zip code. But I can't get it to zoom to the svg. I could zoom in using Google's API, but that's not what I need. I need to zoom in to the svg since there are data in there that needs to show in linear color. The following is my code so far:
function zoomtoZipCode(){
var counties = d3.select("svg").select("g") //apply zoom here.
.call(d3.behavior.zoom().scaleExtent([1, 7])
.on("zoom", zoom))
.selectAll(".counties")
.data(conus.features)
.enter()
}
function zoom(){
var p = d3.select("path")[0];
d3.select(p).attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
Appreciate any assistance. Thanks.
I needed to define my zoom variable and use the terms in d3.js version 4 as follows:
var zoom = d3.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed2);
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.call(zoom);
function zoomed2() {
d3.select("#svgMap2").select("g").selectAll(".county")
.text("text", function (d) { return d.properties.County; })
.attr("transform", d3.event.transform)
.select(".county").style("stroke-width", .5 / d3.event.transform.k + "px");
}

d3 zoom: disable mouse drag?

I want zoom + brush on a bar chart. I was able to implement zooming ok: demo here, but I found out that after zooming, when you mouse down to drag, the bar chart moves. I don't want the bar chart to move on mouse drag. I want the bar chart to stay in its original place and I want to use the mouse drag for brushing. The bar chart could probably scroll left and right, but it should not be dragged left and right.
How do I make the bar chart stay in its original place?
My code snippet is below. Full script here (134 lines)
var zoom = d3.behavior.zoom()
.x(x)
.scaleExtent([0.8, 10])
.on("zoom", zoomed);
function zoomed() {
// scale x axis
svg.select(".x.axis").call(xAxis);
// scale the bars
var width_scaled = columnwidth * d3.event.scale;
svg.selectAll(".bargroup rect")
.attr("x", function(d) {return x(d.date) - width_scaled/2;})
.attr("width", width_scaled);
}
var brush = d3.svg.brush()
.x(x)
.on("brush", brushed);
function brushed() {
//console.log(brush.extent());
}
var svg = d3.select("#timeline").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
svg.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height + 7);

Resources