I am trying to use brush to zoom my custom chart in d3.js but its not behaving the way it should.Any idea what could be wrong here is js fiddle http://fiddle.jshell.net/saurabh_nitc10/od8gfsd3/9/
like in this fiddle http://fiddle.jshell.net/CjaD3/1/ after brushing the bars are going out of yaxis. any idea
what is wrong with the existing fiddle.Its not behaving the way it is supposed to do after zooming.please help.I just updated the fiddle
here is the plugin I have created.
(function($) {
$.dualAxis = {};
var xMapObject=[];
var svg = '';
var focus = '';
var tip = '';
function DualAxis(element, options) {
this.$element = $(element);
this.options = options;
this.margin = {top: 20, right: 80, bottom: 30, left: 40},
width = $(this.$element.selector).width() - this.margin.left - this.margin.right,
height = $(this.$element.selector).height() - this.margin.top - this.margin.bottom;
this.options.height = (this.options.height == null? height: this.options.height);
this.options.width = (this.options.width == null? width: this.options.width);
this.rangeMax = this.getMaxX().length*100;
if (this.rangeMax > 14000) this.rangeMax = 14000;
this.enabled = true;
}
DualAxis.prototype = {
draw: function(){
this.options.data.bar.forEach(function(d) {
d.value = +d.value;
});
this.options.data.line.forEach(function(d) {
d.value = +d.value;
});
tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d) {
var name= xMapObject[d.date];if(name == undefined){name=d.date;}
var table = '<table class="table table-condensed">'
+ '<thead>'
+ '<tr><th colspan="2" style="text-align:center"class="city">'+name+'</th></tr>'
+ '</thead>'
+ '<tbody>'
+ '<tr><td>Total Sales</td><td class="visits">'+d.value+'</td></tr>'
+ '</tbody>'
+ '</table>';
return table;
})
.style({border: '1px solid #fff', 'box-shadow': '1px 1px 4px rgba(0,0,0,0.5)', 'border-radius': 'none','background':'#fff','color':'#555'})
.offset([-12, 0]);
// if(this.options.data.events.length > 1){
// xOffset = (this.options.width/this.options.data.events.length) + 40;
// } else {
// xOffset = this.options.width/2;
// }
xOffset = 62;
svg = this.getSvg();
svg == null ? svg = d3.select(this.$element.selector).append("svg"): svg;
svg = svg
.attr("height", this.options.height+this.margin.bottom+this.margin.top)
.attr("width",this.options.width+this.margin.right+this.margin.left)
.attr('class',this.options.svgClassName);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", this.options.width)
.attr("height", this.options.height);
focus = svg.append("g").attr("class", "focus").attr("transform", "translate(" + xOffset + "," + 40 + ")");
svg.call(tip);
//this.drawBackground(focus);
this.drawRect(focus,tip);
this.drawXAxis(focus);
this.drawY1Axis(focus);
this.drawY2Axis(focus);
this.drawLine(focus);
this.drawLineLow(focus);
this.drawLineMedium(focus);
this.drawLineHigh(focus);
if (this.options.showLegend)this.drawLegend(focus);
this.zoomBehaviour(focus);
},
drawRect: function(svg,tip){
x = this.getX();
x2 = this.getX();
y1 = this.getY1();
y2 = this.getY2();
height = this.options.height - (this.options.height / 3);
transTime = 0;
if(this.options.animate) transTime = 1000;
svg.selectAll("rect.bar").data(this.options.data.bar).enter().append("rect").attr("class","bar").attr("width", this.options.width/this.options.data.bar.length).attr("x", function (d) {
return x(d.date);
}).attr("y", height).attr("height", 0).style("fill", function (d,i) {
return "#89A54E";
}).on('mouseover', tip.show)
.on('mouseout', tip.hide).transition().duration(transTime).attr("y", function (d) {
if(isNaN(y1(d.value))) return 0;return y1(d.value);
}).attr("height", function (d) {
if(isNaN(y1(d.value))) return 0; return (height - y1(d.value));
}).style("fill", function(d) { return "#89A54E";}).attr("rx","1.5").attr("ry","1.5");
},
drawXAxis:function(svg){
svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")").call(this.getXAxis()).append("text").attr("transform", "translate(" + xOffset + "," + 40 + ")").style("text-anchor", "end").text(this.options.xAxisText).style("font-weight", "bold");
},
drawY1Axis:function(svg){
svg.append("g").attr("class", "y axis").call(this.getY1Axis()).append("text").attr('id','y1AxisText').attr("transform", "rotate(-90)").attr("y",-36 ).attr("x", -(this.options.height/5)).style("text-anchor", "end").style("fill", "#266866").style("font-weight", "bold").style("letter-spacing", "1px").text(this.options.y1AxisText);
},
drawY2Axis:function(svg){
svg.append("g").attr("class", "y axis").call(this.getY2Axis()).attr("transform", "translate(" + this.options.width + " ,0)") .append("text").attr('id','y2AxisText').attr("transform", "rotate(-90)").attr("y",47 ).attr("x", -(this.options.height/5)).style("text-anchor", "end").style("fill", "#266866").style("font-weight", "bold").style("letter-spacing", "1px").text(this.options.y2AxisText);
},
drawLegend: function(svg){
legend = svg.append("g").attr("class", "legend").attr('transform', 'translate(-30,'+(height+50)+')');
max = d3.max(this.options.values,function(d){return d.length;});
legend.selectAll('rect').data(this.options.values).enter().append("rect").attr("x", function(d,i){return (i*149);}).attr("y", "0").attr("width", 12).attr("height", 12).style("fill", function(d,i){return color(i);});
legend.selectAll('text').data(this.options.values).enter().append("text").attr("x", function (d, i) {return (i*149+15);}).attr("y", "10").text(function (d) {return d;});
},
getSvg: function(){
return this.options.svg;
},
getXAxis:function(){
//var x = d3.scale.ordinal().rangeRoundBands([0, this.options.width], 0);
return d3.svg.axis().scale(x).tickFormat(d3.time.format("%b'%y")).orient("bottom");
//return d3.svg.axis().scale(x).tickValues(x.domain().filter(function(d, i) {return !(i % 10); })).orient("bottom");
},
getY1Axis:function(){
return d3.svg.axis().scale(y1).orient("left").tickFormat(d3.format(".2s"));
},
getY2Axis:function(){
return d3.svg.axis().scale(y2).orient("right").tickFormat(d3.format(".2s"));
},
getMaxX: function(){ //for ordinal we dont know what to scale
return this.options.data.dateForxAxis.map(function (d) {
return d.date;});
},
getMaxY1: function(){
return d3.max(this.options.data.bar, function (d) {return d.value;});
},
getMaxY2: function(){
return d3.max(this.options.data.line, function (d) {return d.value;});
},
getX: function(){
return d3.time.scale().range([0, this.options.width]).domain(d3.extent(this.options.data.dateForxAxis, function(d) { return d.date; }));
},
getY1: function(){
return d3.scale.linear().range([this.options.height - (this.options.height / 3), 0]).domain([0, this.getMaxY1()]);
},
getY2: function(){
return d3.scale.linear().range([this.options.height - (this.options.height / 3), 0]).domain([0, this.getMaxY2()]);
},
drawBackground: function(vis){
vis.append("rect").attr("x", 0).attr("y", 0).attr("width", this.options.width ).attr("height", this.options.height - 50).style("fill", "grey").attr("transform", "translate(0,0)").style("opacity", "0").attr("class","background").attr("id", "background");
},
zoomBehaviour: function(vis){
var that = this;
//zoomBehaviour = d3.behavior.zoom().scaleExtent([1, 1]).on("zoom", zoom);
brush = d3.svg.brush().x(x2).on("brush", brushed);
width = this.options.width;
vis.append("g").attr("class","x brush").call(brush).selectAll("rect").attr("y",-6).attr("height",this.options.height+7);
function brushed(){
x.domain(brush.empty() ? x2.domain() : brush.extent());
vis.selectAll("rect.bar")
.attr("transform", function(d) { return "translate(" + x(d.date) + ",0)"; })
vis.select(".x.axis").call(that.getXAxis());
//vis.select(".line").attr("d", that.getLine());
}
},
drawLine:function(svg){
svg.append('path').datum(this.options.data.line).attr("class", "line").attr("d", this.getLine());
},
getLine:function(){
return d3.svg.line().interpolate("basis") .x(function(d) {return x(d.date); }).y(function(d) { return y2(d.value); });
},
drawLineLow:function(svg){
svg.append('path').datum(this.options.data.future).attr("class", "lineLow").attr("d", this.getLineLow()).style("stroke-dasharray", ("3, 3"));
},
getLineLow:function(){
return d3.svg.line().interpolate("basis") .x(function(d) {return x(d.date); }).y(function(d) { return y2(d.low); });
},
drawLineMedium:function(svg){
svg.append('path').datum(this.options.data.future).attr("class", "lineMedium").attr("d", this.getLineMedium());
},
getLineMedium:function(){
return d3.svg.line().interpolate("basis") .x(function(d) {return x(d.date); }).y(function(d) { return y2(d.medium); });
},
drawLineHigh:function(svg){
svg.append('path').datum(this.options.data.future).attr("class", "lineHigh").attr("d", this.getLineHigh()).style("stroke-dasharray", ("3, 3"));
},
getLineHigh:function(){
return d3.svg.line().interpolate("basis") .x(function(d) {return x(d.date); }).y(function(d) { return y2(d.high); });
},
};
$.fn.dualAxis = function(options){
options = $.extend({}, $.fn.dualAxis.defaults, options);
if(options.data === '' || options.data === null){
var err = 'dualAxis Error: Data Attribute Cannot be Empty or Null.';
(typeof(console) != 'undefined' && console.error) ?
console.error(err) :
alert(err);
}
function elementOptions(ele, options) {
return $.metadata ? $.extend({}, options, $(ele).metadata()) : options;
};
function get(ele) {
var gb = $.data(ele, 'gb');
if (!gb) {
gb = new DualAxis(ele,elementOptions(ele, options));
$.data(ele, 'gb', gb);
}
return gb;
}
var gb = get(this);
gb.draw();
};
$.fn.dualAxis.defaults = {
svgClassName: "dualAxis",
svg: null,
xAxisText: 'x-axis',
y1AxisText: 'y1-axis',
y2AxisText: 'y2-axis',
maxX: null,
maxyY: null,
height:null,
width:null,
animate: true,
color: ["#3366cc", "#dc3912", "#ff9900", "#109618"],
showLegend:true,
data: '',
};
})(jQuery);
here is the format of data
{
"bar": [
{
"date": "50_2012",
"value": "88787"
},
{
"date": "155_2012",
"value": "50573"
},
{
"date": "155_2013",
"value": "5057"
}
],
"dateForxAxis": [
{
"date": "45_2012"
},
{
"date": "155_2012"
},
{
"date": "260_2013"
}
],
"future": [
{
"high": "87878",
"medium": "55535",
"low": "1212"
},
{
"high": "187878",
"medium": "255535",
"low": "14212"
}
],
"line": [
{
"date": "50_2012",
"value": "8787"
},
{
"date": "60_2012",
"value": "47474"
},
{
"date": "168_2012",
"value": "49474"
}
]
};
calling the plugin
$('#dualAxis').dualAxis({
data: viewData1,
xAxisText: 'Time',
y1AxisText:'Transactions',
y2AxisText:'Sales',
animate:true,
showLegend:false
});
Please suggest what Am I doing wrong.when it is zooming it should zoom even for line bar and the three other lines.
In the brushed method, you are translating the bars instead of setting a new x position (causing them to be translated based on their original x position outside the graph). Re-setting the x position in the brushed method will place the bars correctly when scaling:
vis.selectAll("rect.bar").attr("x", function (d) {
return x(d.date);
});
A fork of your jsfiddle with this change at http://fiddle.jshell.net/brendaz/zr6kkgaa/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With