I was busting my head on this problem for some time...
I have a usual constructor/prototype object (like a class) in js which holds all of my d3 chart logic:
figureGen = function(html_element) {
this.svg = d3.select(html_element)
.append('svg')
.style('width', '100%')
.style('height', '100%')
.append('g')
.attr("class", "sadrzalac")
.attr("transform", "translate(" + 0 + "," + 0 + ")");
this.element = element;
this.data = [];
this.yRange = d3.scale.linear();
this.xRange = d3.scale.linear();
this.xAxis = undefined;
this.yAxis = undefined;
this.width = undefined;
this.height = undefined;
this.zoom = undefined;
this.margin = {top: 20, right: 20, bottom: 20, left: 35};
this.svg.append("rect")
.attr("class", "clipPath")
.attr("transform", "translate(" + this.margin.left + "," + -this.margin.top + ")");
this.svg.append('g')
.attr("class","xaxis axis");
this.svg.append('g')
.attr("class", "yaxis axis");
}
for the constructor, and for the methods something like this
figureGen.prototype = {
constructor: figureGen,
init: function(sampledata, width, height){
var y_min = Number(d3.min(this.podaci, function (d) { return d.y;}));
var y_max = Number(d3.max(this.podaci, function (d) { return d.y;}));
var x_min = Number(d3.min(this.podaci, function (d) { return d.x;}));
var x_max = Number(d3.max(this.podaci, function (d) { return d.x;}));
var ukupan_opseg = y_max - y_min;
var spacer = (ukupan_opseg*25)/100;
this.xRange = d3.scale.linear().range([this.margin.left + 10, this.width - this.margin.right]).domain([x_min, x_max]);
this.yRange = d3.scale.linear().range([this.height - this.margin.top, this.margin.bottom]).domain([y_min-spacer, y_max+spacer]);
this.zoom = d3.behavior.zoom()
.x(this.xRange)
.y(this.yRange)
.scaleExtent([1, 5])
.center([this.width / 2, this.height / 2])
.size([this.width, this.height])
.on("zoom", this.zoomProcess());
this.svg
.attr("width", this.sirina)
.attr("height", this.visina)
.call(this.zoom);
this.xAxis = d3.svg.axis()
.scale(this.xRange)
.innerTickSize(-this.height+40)
.outerTickSize(5)
.tickPadding(10)
.tickFormat(d3.format("d"));
this.yAxis = d3.svg.axis()
.scale(this.yRange)
.orient("left")
.innerTickSize(-this.width)
.outerTickSize(5)
.tickPadding(10)
.tickSubdivide(false);
this.svg.select('.xosa')
.attr("transform", "translate(0," + (this.height - this.margin.bottom) + ")")
.call(this.xAxis);
this.svg.select(".yosa")
.attr("transform", "translate(" + (this.margin.left) + ",0)")
.call(this.yAxis);
},
zoomProcess: function{
this.svg.select(".xaxis").call(this.xAxis);
this.svg.select(".yaxis").call(this.yAxis);
console.log(this.svg);
}
}
and the problem is in the zoomProcess method which always returns (logs) HTML element on the this.svg instead of this.svg object which can .select. Zoom behaviour is properly attached to my element, and on mouse whell the zooming starts but it pops up an error saying that this .call on this.xAxis can't be performed.
What's even stranger when I trigger zoomProcess from another source, like a button click its console log outputs the proper this.svg object and not the HTML element, so it seems that the error comes from the zoom event handler. What's wrong here?
These are the two examples I've been looking at:
http://bl.ocks.org/stepheneb/1182434
http://bl.ocks.org/mbostock/7ec977c95910dd026812
EDIT: Now I guess that I probably should use .bind() on the this object so that its reference stays the same when going to zoomProcedura method. Still I`m not sure how to do this.
I assume there is a typo that is not in your actual code...
zoomProcess: function{
this.svg.select(".xaxis").call(this.xAxis);
this.svg.select(".yaxis").call(this.yAxis);
console.log(this.svg);
}
is probably...
zoomProcess: function(){
this.svg.select(".xaxis").call(this.xAxis);
this.svg.select(".yaxis").call(this.yAxis);
console.log(this.svg);
}
or maybe...
zoomProcess: function(){
return function() {
this.svg.select(".xaxis").call(this.xAxis);
this.svg.select(".yaxis").call(this.yAxis);
console.log(this.svg);
}
}
I can't know for certain. And I assume you really are invoking like...
.on("zoom", this.zoomProcess());
Not...
.on("zoom", this.zoomProcess);
But anyway, based on that assumption, to make it work the way you want, try...
zoomProcess: function(){
//'this' is figureGen.prototype
var that = this;
return function () {
//'this' is window
that.svg.select(".xaxis").call(that.xAxis);
that.svg.select(".yaxis").call(that.yAxis);
console.log(that.svg);
}
}
or...
zoomProcess: function(){
//'this' is figureGen.prototype
return function () {
//'this' is figureGen.prototype
this.svg.select(".xaxis").call(this.xAxis);
this.svg.select(".yaxis").call(this.yAxis);
console.log(this.svg);
}.bind(this)
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.