|
// Chart design based on my BulleT that was based on original bullet chart by Mike Bostock: |
|
// http://bl.ocks.org/mbostock/4061961 |
|
// with d3.chart.js (0.1.2) |
|
// http://misoproject.com/d3-chart/ |
|
d3.chart("LikertEven", { |
|
initialize: function() { |
|
var chart = this; |
|
this.xScale = d3.scale.linear(); |
|
this.tickFormat( function(d){return Math.abs(d)} ); |
|
this.x0 = chart.xScale(0); |
|
this.axisStyle(function(d) { |
|
return d.axisStyle; |
|
}); |
|
this.base.classed("LikertEven", true); |
|
// Default configuration |
|
this._margin = { top: 0, right: 0, bottom: 0, left: 0 }; |
|
this.duration(0); |
|
this.percent(function(d) { |
|
return d.percent; |
|
}); |
|
this.width(100); |
|
this.height(40); |
|
this.reverse(false); |
|
this.orient("left"); |
|
this.terjedelem(function(d) { |
|
return d.terjedelem; |
|
}); |
|
/******************************************************************************/ |
|
this.layer("rowBackgroundA", this.base.append("g").classed("rowBackgroundA", true), { |
|
dataBind: function(data) { |
|
data = data.rowStyle; |
|
return this.selectAll("rect").data(data); |
|
}, |
|
insert: function() { |
|
return this.append("g"); |
|
}, |
|
events: { |
|
enter: function(d) { |
|
this.append("rect").attr("class", function(d){return d;}) |
|
.attr("x", chart.xScale(-110)) |
|
.attr("y", 0) |
|
.attr("height", chart.height()) |
|
.attr("width", chart.xScale(250)); |
|
this.append("rect").attr("class", function(d){ |
|
var axisStyle = chart.axisStyle(); |
|
if( axisStyle === "axis" ){ |
|
return "background " + d; |
|
}else{ |
|
return "background " + "white"; |
|
} |
|
}) |
|
.attr("x", chart.xScale(100)) |
|
.attr("y", chart.height()/2) |
|
.attr("height", chart.height()/2) |
|
.attr("width", chart.xScale(40)); |
|
} |
|
} |
|
}) |
|
/******************************************************************************/ |
|
this.layer("rowBackgroundB", this.base.append("g").classed("rowBackgroundB", true), { |
|
dataBind: function() { |
|
var format = this.chart().tickFormat(); |
|
return this.selectAll("g.tickLine").data(this.chart().xScale.ticks(8), function(d) { |
|
return d; |
|
}); |
|
}, |
|
insert: function() { |
|
var tick = this.append("g").attr("class", "tickLine"); |
|
var height =chart.height(); |
|
var format = chart.tickFormat(); |
|
tick.append("line") |
|
.attr("y1", 0) |
|
.attr("y2", chart.height()) |
|
.attr("opacity", function(d) { |
|
if( d < 100 ){ |
|
return 1; |
|
}else{ |
|
return 0; |
|
} |
|
}); |
|
return tick; |
|
}, |
|
events: { |
|
enter: function(d) { |
|
var axisStyle = chart.axisStyle(); |
|
this.attr("transform", function(d) { |
|
return "translate(" + chart.xScale(d) + ",0)"; |
|
}) |
|
.attr("stroke-width", 1) |
|
.attr("stroke", "#ffffff"); |
|
}, |
|
"exit:transition": function() { |
|
this.remove(); |
|
} |
|
} |
|
}) |
|
/******************************************************************************/ |
|
this.layer("percent", this.base.append("g").classed("percent", true), { |
|
dataBind: function(data) { |
|
var data_percent = new Array(); |
|
// @CodeXmonk: a bit of hack too - ToDo later. |
|
data_percent[0] = (data.percent[0]+data.percent[1])*(-1); // [-80,-45,20,40] |
|
data_percent[1] = data.percent[1]*(-1); |
|
data_percent[2] = data.percent[2]+data.percent[3]; |
|
data_percent[3] = data.percent[2]; |
|
return this.selectAll("rect.percent").data(data_percent); |
|
}, |
|
insert: function() { |
|
return this.append("rect"); |
|
}, |
|
events: { |
|
enter: function(d, i) { |
|
this.attr("class", function(d, i) { return "percent s" + i; }) |
|
.attr("height", chart.height()) |
|
.attr("x", function(d,i) { |
|
if( d < 0 ){ |
|
return chart.xScale(d); |
|
}else{ |
|
return chart.xScale(0); |
|
} |
|
}) |
|
.attr("width", function(d, i) { |
|
return chart.xScale(Math.abs(d))-chart.xScale(0) ; |
|
}) |
|
.attr("transform", "translate(" + 0 + ",0)" ); |
|
}, |
|
"merge:transition": function(d, i) { |
|
this.duration(chart.duration()) |
|
.attr("x", function(d, i) { |
|
if( d < 0 ){ |
|
return chart.xScale(d); |
|
}else{ |
|
return chart.xScale(0); |
|
} |
|
}) |
|
.attr("width", function(d, i) { |
|
if( d < 0 ){ |
|
return chart.xScale(Math.abs(d))-chart.xScale(0) ; |
|
}else{ |
|
return chart.xScale(Math.abs(d))-chart.xScale(0) ; |
|
} |
|
}) |
|
.attr("transform", "translate(" + 0 + ",0)" ); |
|
}, |
|
exit: function() { |
|
this.remove(); |
|
} |
|
} |
|
}); |
|
/******************************************************************************/ |
|
this.layer("text", this.base.append("g").classed("text", true), { |
|
dataBind: function(data) { |
|
var data_percent = new Array(); |
|
var dimension = data.dimension; |
|
var axisStyle = chart.axisStyle(); |
|
// @CodeXmonk: a bit of hack too - ToDo later. |
|
data_percent[0] = new Array( (data.percent[0]+data.percent[1])*(-1), data.percent[0], dimension ); // [-80,-45,20,40] |
|
data_percent[1] = new Array( data.percent[1]*(-1), data.percent[1], dimension ); |
|
data_percent[2] = new Array( data.percent[2]+data.percent[3], data.percent[3], dimension ); |
|
data_percent[3] = new Array( data.percent[2], data.percent[2], dimension); |
|
return this.selectAll("text").data(data_percent); |
|
}, |
|
insert: function() { |
|
return this.append("text") |
|
}, |
|
events: { |
|
enter: function(d, i) { |
|
this.text( function(d,i) { |
|
var axisStyle = chart.axisStyle(); |
|
if( axisStyle === "axis" ){ |
|
return d[2][i+1]; |
|
}else{ |
|
switch (true) |
|
{ |
|
case ( d[1] < 5 ): |
|
return ""; |
|
break; |
|
case ( 5 <= d[1] && d[1] < 8 ): |
|
return Math.abs(d[1]); |
|
break; |
|
default: |
|
return Math.abs(d[1])+"%"; |
|
break; |
|
} |
|
} |
|
}) |
|
.style("opacity", function() { |
|
var axisStyle = chart.axisStyle(); |
|
if( axisStyle === "axis" ){ |
|
return 1; |
|
}else{ |
|
return 0; |
|
} |
|
}) |
|
this.attr("class", function(d, i) { |
|
var axisStyle = chart.axisStyle(); |
|
if( axisStyle === "axis" ){ |
|
return "textResultKiem"; |
|
}else{ |
|
return "textResult"; |
|
} |
|
}) |
|
.attr("y", chart.height() - chart.height()/3) |
|
.attr("x", function(d, i) { |
|
return chart.xScale(d[0]); |
|
}) |
|
.attr("text-anchor", function(d, i) { |
|
if( d[0] < 0 ){ |
|
return "start"; |
|
}else{ |
|
return "end"; |
|
} |
|
}) |
|
.attr("transform", function(d, i) { |
|
if( d[0] < 0 ){ |
|
return "translate(" + 2 + ",0)"; |
|
}else{ |
|
return "translate(" + -2 + ",0)"; |
|
} |
|
}); |
|
}, |
|
"merge:transition": function(d, i) { |
|
this.duration(chart.duration()) |
|
.attr("x", function(d, i) { |
|
return chart.xScale(d[0]); |
|
}) |
|
.attr("text-anchor", function(d, i) { |
|
if( d[0] < 0 ){ |
|
return "start"; |
|
}else{ |
|
return "end"; |
|
} |
|
}) |
|
.attr("transform", function(d, i) { |
|
if( d[0] < 0 ){ |
|
return "translate(" + 2 + ",0)"; |
|
}else{ |
|
return "translate(" + -2 + ",0)"; |
|
} |
|
}); |
|
this.duration(chart.duration()*2) |
|
.style("opacity", function(d){return 1;}); |
|
}, |
|
exit: function() { |
|
this.remove(); |
|
} |
|
} |
|
}); |
|
/******************************************************************************/ |
|
this.layer("textLegendA", this.base.append("g").classed("textLegendA", true), { |
|
dataBind: function(data) { |
|
var data_tmp = new Array(); |
|
var dimension = data.dimension; |
|
var axisStyle = chart.axisStyle(); |
|
data_tmp[0] = new Array( dimension ); |
|
return this.selectAll("text").data(data_tmp); |
|
}, |
|
insert: function() { |
|
return this.append("text"); |
|
}, |
|
events: { |
|
enter: function(d) { |
|
this.text( function(d) {return d[0][0];}); |
|
this.attr("class", function() { |
|
var axisStyle = chart.axisStyle(); |
|
if( axisStyle === "axis" ){ |
|
return "dimTextKiem"; |
|
}else{ |
|
return "textLegendA"; |
|
} |
|
}) |
|
this.attr("y", function() { |
|
var axisStyle = chart.axisStyle(); |
|
if( axisStyle === "axis" ){ |
|
return chart.height()/1.5; |
|
}else{ |
|
return chart.height()/2.8; |
|
} |
|
}) |
|
.attr("x", function() { return chart.xScale(104);}) |
|
.attr("text-anchor", function() {return "start"; }); |
|
}, |
|
"merge:transition": function() { |
|
this.attr("x", function() { |
|
return chart.xScale(104); |
|
}) |
|
.attr("text-anchor", function() {return "start"; }); |
|
}, |
|
exit: function() { |
|
this.remove(); |
|
} |
|
} |
|
}); |
|
/******************************************************************************/ |
|
this.layer("textLegendB", this.base.append("g").classed("textLegendB", true), { |
|
dataBind: function(data) { |
|
var data_tmp = new Array(); |
|
var axisStyle = chart.axisStyle(); |
|
/* let's find the greatest value in data.percent array */ |
|
var greatest; |
|
var indexOfGreatest; |
|
var array = data.percent; |
|
for (var i = 0; i < array.length; i++) { |
|
if (!greatest || array[i] > greatest) { |
|
greatest = array[i]; |
|
indexOfGreatest = i; |
|
} |
|
} |
|
data_tmp[0] = new Array( data.percent[indexOfGreatest], indexOfGreatest, data.dimension ); |
|
return this.selectAll("text").data(data_tmp); |
|
}, |
|
insert: function() { |
|
return this.append("text"); |
|
}, |
|
events: { |
|
enter: function(d) { |
|
this.text( function(d) { |
|
var idx = d[1]; |
|
var axisStyle = chart.axisStyle(); |
|
if( axisStyle === "axis" ){ |
|
return ""; |
|
}else{ |
|
return d[0] + "% " + d[2][idx+1]; |
|
} |
|
}); |
|
this.attr("class", function(d) { |
|
var idx = d[1]; |
|
return "subtitle s" + idx; |
|
}) |
|
this.attr("y", function() { |
|
var axisStyle = chart.axisStyle(); |
|
if( axisStyle === "axis" ){ |
|
return chart.height()/1.5; |
|
}else{ |
|
return chart.height()-4; |
|
} |
|
}) |
|
.attr("x", function() { return chart.xScale(104);}) |
|
.attr("text-anchor", function() {return "start"; }); |
|
}, |
|
"merge:transition": function() { |
|
this.attr("x", function() { |
|
return chart.xScale(104); |
|
}) |
|
.attr("text-anchor", function() {return "start"; }); |
|
}, |
|
exit: function() { |
|
this.selectAll("text").remove(); |
|
} |
|
} |
|
}); |
|
/******************************************************************************/ |
|
this.layer("ticks", this.base.append("g").classed("ticks", true), { |
|
dataBind: function() { |
|
var format = this.chart().tickFormat(); |
|
return this.selectAll("g.tick").data(this.chart().xScale.ticks(8), function(d) { |
|
return d; |
|
}); |
|
}, |
|
insert: function() { |
|
var tick = this.append("g").attr("class", "tick"); |
|
var height =chart.height(); |
|
var format = chart.tickFormat(); |
|
tick.append("line") |
|
.attr("y1", chart.height()) |
|
.attr("y2", chart.height() * 7 / 6); |
|
tick.append("text") |
|
.attr("text-anchor", "middle") |
|
.attr("dy", "1em") |
|
.attr("y", chart.height() * 7 / 6) |
|
.text(format); |
|
return tick; |
|
}, |
|
events: { |
|
enter: function(d) { |
|
var axisStyle = chart.axisStyle(); |
|
this.attr("transform", function(d) { |
|
return "translate(" + chart.xScale(d) + ",0)"; |
|
}) |
|
.style("opacity", function(d){ |
|
if( axisStyle === "axis" ){ |
|
return 1; |
|
}else{ |
|
return 0; |
|
} |
|
}); |
|
}, |
|
"merge:transition": function(d) { |
|
var axisStyle = chart.axisStyle(); |
|
this.duration(chart.duration()) |
|
.attr("transform", function(d) { |
|
return "translate(" + chart.xScale(d) + ",0)"; |
|
}) |
|
.style("opacity", function(d){ |
|
if( axisStyle === "axis" ){ |
|
return 1; |
|
}else{ |
|
return 0; |
|
} |
|
}); |
|
this.select("line") |
|
.attr("y1", chart.height()) |
|
.attr("y2", chart.height() * 7 / 6); |
|
this.select("text") |
|
.attr("y", chart.height() * 7 / 6); |
|
}, |
|
"exit:transition": function() { |
|
this.duration(chart.duration()) |
|
.attr("transform", function(d) { |
|
return "translate(" + chart.xScale(d) + ",0)"; |
|
}) |
|
.style("opacity", 1e-6) |
|
.remove(); |
|
} |
|
} |
|
}); |
|
|
|
d3.timer.flush(); |
|
}, |
|
|
|
transform: function(data) { |
|
var height = this.height(); |
|
// misoproject: Copy data before sorting |
|
var newData = { |
|
rowStyle: data.rowStyle, |
|
dimension: data.dimension, |
|
randomizer: data.randomizer, |
|
terjedelem: data.terjedelem.slice(), |
|
percent: data.percent, |
|
item: data.item, |
|
}; |
|
this.xScale.domain([newData.terjedelem[0], newData.terjedelem[1]]); |
|
var axisStyle = this.axisStyle(); |
|
if( axisStyle !== "axis" ){ |
|
var select_tmp = d3.selectAll("[name=SVG]"); |
|
select_tmp.attr("height",25); |
|
} |
|
return newData; |
|
}, |
|
|
|
// misoproject: reverse or not |
|
reverse: function(x) { |
|
if (!arguments.length) return this._reverse; |
|
this._reverse = x; |
|
return this; |
|
}, |
|
|
|
// misoproject: left, right, top, bottom |
|
orient: function(x) { |
|
if (!arguments.length) return this._orient; |
|
this._orient = x; |
|
this._reverse = this._orient == "right" || this._orient == "bottom"; |
|
return this; |
|
}, |
|
|
|
axisStyle: function(x) { |
|
if (!arguments.length) return this._axisStyle; |
|
this._axisStyle = x; |
|
return this; |
|
}, |
|
|
|
// @CodeXmonk: terjedelem (20,80) |
|
terjedelem: function(x) { |
|
if (!arguments.length) return this._terjedelem; |
|
this._terjedelem = x; |
|
return this; |
|
}, |
|
|
|
percent: function(x) { |
|
if (!arguments.length) return this._percent; |
|
this._percent = x; |
|
return this; |
|
}, |
|
|
|
width: function(x) { |
|
var margin, width_tmp; |
|
if (!arguments.length) { |
|
return this._width; |
|
} |
|
margin = this.margin(); |
|
width_tmp = x[0]; |
|
width_tmp = width_tmp - (margin.left + margin.right); |
|
this._width = width_tmp; |
|
this.xScale.range(this._reverse ? [width_tmp, 0] : [0, width_tmp]); |
|
this.base.attr("width", width_tmp); |
|
return this; |
|
}, |
|
|
|
height: function(x) { |
|
var margin, height_tmp; |
|
if (!arguments.length) { |
|
return this._height; |
|
} |
|
margin = this.margin(); |
|
height_tmp = x[0]; |
|
height_tmp = height_tmp - (margin.top + margin.bottom)-10; |
|
this._height = height_tmp; |
|
this.base.attr("height", height_tmp); |
|
return this; |
|
}, |
|
|
|
margin: function(margin) { |
|
if (!margin) { |
|
return this._margin; |
|
} |
|
var margin_tmp = margin; |
|
["top", "right", "bottom", "left"].forEach(function(dimension) { |
|
if (dimension in margin_tmp) { |
|
this._margin[dimension] = margin_tmp[dimension]; |
|
} |
|
}, this); |
|
this.base.attr("transform", "translate(" + this._margin.left + "," + this._margin.top + ")"); |
|
return this; |
|
}, |
|
|
|
tickFormat: function(x) { |
|
if (!arguments.length) return this._tickFormat; |
|
this._tickFormat = x; |
|
return this; |
|
}, |
|
|
|
orientation: function(x) { |
|
if (!arguments.length) return this._orientation; |
|
this._orientation = x; |
|
return this; |
|
}, |
|
|
|
duration: function(x) { |
|
if (!arguments.length) return this._duration; |
|
this._duration = x; |
|
return this; |
|
} |
|
}); |