2592 lines
85 KiB
JavaScript
2592 lines
85 KiB
JavaScript
function drawAxisX(data, canvas, scale, parameter){
|
|
if (!parameter.graph.axisX.showAxis) return;
|
|
//graph Dimensions inside the container
|
|
var graphDim = new GraphDim(parameter);
|
|
var xAxis = d3.svg.axis().scale(scale).orient('bottom').tickSize(parameter.graph.axisX.ticks);
|
|
|
|
var x_axis = canvas.append('g')
|
|
.attr('class', 'axis')
|
|
.attr('transform','translate(0,' + graphDim.bottom + ')')
|
|
.call(xAxis)
|
|
.selectAll('text')
|
|
.style('text-anchor','end')
|
|
.attr('class', 'x-ticks-label')
|
|
.attr('transform','rotate(-45)');
|
|
|
|
|
|
if (parameter.graph.axisX.showLabel) {
|
|
var labelPosX = graphDim.left + graphDim.width/2;
|
|
var labelPosY = graphDim.bottom + 55
|
|
canvas.append("text")
|
|
.attr("transform", "translate(" + labelPosX + " ," + labelPosY + ")")
|
|
.attr('class','axis-label')
|
|
.style("text-anchor", "middle")
|
|
.text(parameter.graph.axisX.label);
|
|
}
|
|
}
|
|
|
|
function drawAxisY(data, canvas, scale, parameter){
|
|
if (!parameter.graph.axisY.showAxis) return;
|
|
var graphDim = new GraphDim(parameter);
|
|
var yAxis = d3.svg.axis().scale(scale).orient('left').ticks(parameter.graph.axisY.ticks);
|
|
var y_axis = canvas.append('g')
|
|
.attr('class','axis')
|
|
.attr('transform','translate(' + graphDim.top + ',0)')
|
|
.call(yAxis)
|
|
.selectAll('text')
|
|
.attr('class', 'y-ticks-label');
|
|
|
|
|
|
if (parameter.graph.axisY.showLabel) {
|
|
canvas.append("text")
|
|
.attr('class','axis-label')
|
|
.attr("transform", "rotate(-90)")
|
|
.attr("y", 0)
|
|
.attr("x", -(graphDim.left + graphDim.height/2))
|
|
.attr("dy", "1.5em")
|
|
.style("text-anchor", "end")
|
|
.text(parameter.graph.axisY.label);
|
|
}
|
|
}
|
|
|
|
|
|
var BarChart = function (data, params, previousDataPoint, breadcrumbs) {
|
|
this.originalData = data;
|
|
this.previousDataPoint = previousDataPoint;
|
|
this.params = params;
|
|
this.$container = $('#' + this.params.canvas.containerId);
|
|
//Breadcrumb stack:
|
|
this.breadCrumbStack = (breadcrumbs == null ) ? [] : breadcrumbs;
|
|
pushToStack(previousDataPoint, this);
|
|
};
|
|
|
|
BarChart.prototype.drawChart = function() {
|
|
var $container = $('#' + this.params.canvas.containerId); // canvas[0] to convert d3 to jquery object
|
|
$container.empty();
|
|
$('.tooltipdiv').remove();
|
|
stretchCanvas(null, this.$container, this.params);
|
|
this.canvas = createCanvas(this.params.canvas.containerId, this.params.canvas);
|
|
this.drawBars(this.originalData, this.canvas, this.params);
|
|
refreshBreadCrumbs(this);
|
|
};
|
|
|
|
BarChart.prototype.addBarTransition = function (bars, scaleX, scaleY) {
|
|
|
|
/************* IN TRANSITION ****************/
|
|
bars.attr("stroke-width", 4)
|
|
.transition()
|
|
.duration(300)
|
|
.attr("width", scaleX.rangeBand())
|
|
.attr("y", function (d) { return scaleY(d.value) });
|
|
|
|
/*************** EXIT TRANSITION *****************/
|
|
bars.exit()
|
|
.transition()
|
|
.duration(300)
|
|
.ease("exp")
|
|
.attr("width", 0)
|
|
.remove();
|
|
}
|
|
|
|
BarChart.prototype.drawBars = function(data, canvas, param) {
|
|
var parameter = createDefaultParamsForGraph(param);
|
|
//graph part of the parameters passed to this object
|
|
var graphParam = createDefaultParamsForLineChart(param.graph);
|
|
parameter.graph = graphParam;
|
|
|
|
//graph Dimensions inside the container
|
|
var graphDim = new GraphDim(param);
|
|
|
|
/*var totalPaddingTop = DEFAULT_PADDING + parameter.graph.paddingTop;
|
|
var h = parameter.canvas.height - totalPaddingTop - DEFAULT_PADDING;
|
|
var w = parameter.canvas.width - 2 * DEFAULT_PADDING;
|
|
var chartRight = w + DEFAULT_PADDING;
|
|
var chartBottom = h + totalPaddingTop;
|
|
*/
|
|
var tooltip = new ToolTip();
|
|
//HACK: to avoid context change in closure we store object's reference(this) here.
|
|
// JavaScript things...
|
|
var currObj = this;
|
|
|
|
if (data == null || data.length == 0) {
|
|
canvas.append("text")
|
|
.attr('class','pm-charts-no-draw')
|
|
.attr("y", graphDim.height/2)
|
|
.attr("x", graphDim.left*2 + graphDim.width/2)
|
|
.attr("dy", "1.5em")
|
|
.style("text-anchor", "end")
|
|
.text("No data to draw...");
|
|
data = [ {"value":"0", "datalabel":"None"} ];
|
|
}
|
|
|
|
var xScaleLabels = data.map(function(data){
|
|
return data.datalabel;
|
|
});
|
|
|
|
var maxValue = d3.max(data,function(d){ return d.value*1.0; });
|
|
|
|
var xScale = d3.scale
|
|
.ordinal()
|
|
.domain(xScaleLabels)
|
|
.rangeRoundBands([graphDim.left,graphDim.right], 0.15);
|
|
|
|
var yScale = d3.scale
|
|
.linear()
|
|
.domain( [0, maxValue] )
|
|
.range([graphDim.bottom, graphDim.top])
|
|
.nice();
|
|
|
|
var chart = canvas.append('g');
|
|
/*chart.append("text")
|
|
.attr('class','pm-charts-no-draw')
|
|
.text("No data to draw!");*/
|
|
|
|
var graphDim = new GraphDim(parameter);
|
|
|
|
drawAxisX(data, chart, xScale, parameter);
|
|
drawAxisY(data, chart, yScale, parameter);
|
|
drawLinesX(data, chart, xScale, parameter);
|
|
drawLinesY(data, chart, yScale, parameter);
|
|
|
|
var bars = chart.selectAll('rect').data(data);
|
|
if (parameter.graph.allowZoom) { addZoomToCanvas(chart); }
|
|
addGradient(chart, "gradientForBars")
|
|
|
|
bars.enter()
|
|
.append('rect')
|
|
.attr({
|
|
'x': function(d,i) {
|
|
return xScale(d.datalabel);
|
|
},
|
|
'y': function(d) {
|
|
return (parameter.graph.allowTransition) ? 0 : yScale(d.value);
|
|
},
|
|
'width': (parameter.graph.allowTransition) ? 0: xScale.rangeBand(),
|
|
'height': function(d) {
|
|
return graphDim.bottom - yScale(d.value);
|
|
},
|
|
'fill': 'url(#gradientForBars)'
|
|
})
|
|
.attr("clip-path", "url(#rectClip)")
|
|
.on("mouseover", function(d,i) {
|
|
d3.select(this)
|
|
.attr('fill', currObj.params.graph.colorPalette[i%currObj.params.graph.colorPalette.length]);
|
|
|
|
tooltip.show(function () {
|
|
return {value: d.value, datalabel: d.datalabel}
|
|
});
|
|
})
|
|
.on('mouseout',function(d){
|
|
d3.select(this)
|
|
.attr('fill','url(#gradientForBars)');
|
|
tooltip.hide();
|
|
});
|
|
|
|
|
|
if (parameter.graph.allowTransition) {this.addBarTransition(bars, xScale, yScale);}
|
|
|
|
|
|
if (parameter.graph.useShadows){
|
|
addShadow(canvas, "110%", 2);
|
|
chart.selectAll('rect')
|
|
.attr("filter", "url(#drop-shadow)");
|
|
}
|
|
|
|
|
|
|
|
if (this.params.graph.allowDrillDown) {
|
|
this.addOnClick(data, canvas);
|
|
if (this.breadCrumbStack.length > 0) {
|
|
var clip = chart.append("defs")
|
|
.append("svg:clipPath")
|
|
.attr("id", "clip")
|
|
.append("svg:rect")
|
|
.attr("id", "clip-rect")
|
|
.attr("x", "0")
|
|
.attr("y", "0")
|
|
.attr("width", 50)
|
|
.attr("height", 50)
|
|
.transition()
|
|
.duration(2000)
|
|
.attr("width", 500)
|
|
.attr("height", 500);
|
|
d3.select("svg g").attr('clip-path', 'url(#clip)');
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//function used to implement the drill-down
|
|
BarChart.prototype.addOnClick = function (arrayData, canvas) {
|
|
//HACK: to avoid context change in closue we store object's reference(this) here.
|
|
// JavaScript things...
|
|
var currObj = this;
|
|
canvas.selectAll("rect")
|
|
.data(arrayData)
|
|
.on("click", function (pointData) {
|
|
if (pointData.callBack != null && pointData.callBack.length != '') {
|
|
var $container = $(canvas[0]).parent();
|
|
$container.empty();
|
|
$('.tooltipdiv').remove();
|
|
var funCallBack = eval(pointData.callBack);
|
|
funCallBack(pointData, currObj);
|
|
//pushToStack(pointData, currObj);
|
|
}
|
|
});
|
|
};
|
|
|
|
|
|
|
|
var DEFAULT_PADDING = 50;
|
|
|
|
function defaultAxis(axisParam) {
|
|
var retval = {};
|
|
addValueForProperty(retval, axisParam, 'showLabel', true);
|
|
addValueForProperty(retval, axisParam, 'showAxis', true);
|
|
addValueForProperty(retval, axisParam, 'label', 'X');
|
|
addValueForProperty(retval, axisParam, 'ticks', 10);
|
|
return retval;
|
|
}
|
|
|
|
function addValueForProperty(targetObject, baseObject, property, defaultValue) {
|
|
if (property in baseObject) {
|
|
targetObject[property] = baseObject[property];
|
|
}
|
|
else {
|
|
targetObject[property] = defaultValue;
|
|
}
|
|
|
|
}
|
|
|
|
function createDefaultParamsForGraph(param) {
|
|
if (param.canvas == null) {throw new Error('You need specify canvas configuration parameters.');}
|
|
if (param.graph == null) {throw new Error('You need specify graph configuration parameters.');}
|
|
if (param.canvas.width == null) {throw new Error('No canvas width specified.');}
|
|
if (param.canvas.height == null) {throw new Error('No canvas height specified.');}
|
|
|
|
var retval = {
|
|
canvas: {
|
|
width: ("width" in param.canvas) ? param.canvas.width : 100 ,
|
|
height: ("height" in param.canvas) ? param.canvas.height : 100 ,
|
|
exportTo: ("exportTo" in param.canvas) ? param.canvas.exportTo : [],
|
|
stretch: ("stretch" in param.canvas) ? param.canvas.stretch : true
|
|
},
|
|
graph: {
|
|
allowTransition: ("allowTransition" in param.graph) ? param.graph.allowTransition : false,
|
|
allowZoom: ("allowZoom" in param.graph) ? param.graph.allowZoom : false,
|
|
useShadows: ("useShadows" in param.graph) ? param.graph.useShadows : false,
|
|
showTip: ("showTip" in param.graph) ? param.graph.showTip : false,
|
|
paddingTop: ("paddingTop" in param.graph) ? param.graph.paddingTop : 50,
|
|
axisX: ("axisX" in param.graph) ? defaultAxis(param.graph.axisX) : defaultAxis({}),
|
|
axisY: ("axisY" in param.graph) ? defaultAxis(param.graph.axisY) : defaultAxis({}),
|
|
colorPalette: ("colorPalette" in param.graph) ? param.graph.colorPalette : ["#62C1A3", "#FB906B", "#8DA1CB", "#E88AC2", "#E4C18F", "#B3B3B3", "#3180BA", "#50B14D", "#9A51A4", "#F87709", "#A35920","#A6D954", "#FED92F", "#ED2617"]
|
|
},
|
|
linesx: true,
|
|
linesy: true
|
|
};
|
|
return retval;
|
|
/*axisX: ("axisX" in param.graph) ? param.graph.axisX : { showAxis: true, label: "X", showLabel: true, ticks: 5 },
|
|
axisY: ("axisY" in param.graph) ? param.graph.axisY : { showAxis: true, label: "Y", showLable: true, ticks: 5 },*/
|
|
}
|
|
function createDefaultParamsForGraphRign(param) {
|
|
|
|
if (param.canvas == null) {throw new Error('You need specify canvas configuration parameters.');}
|
|
if (param.graph == null) {throw new Error('You need specify graph configuration parameters.');}
|
|
if (param.canvas.width == null) {throw new Error('No canvas width specified.');}
|
|
if (param.canvas.height == null) {throw new Error('No canvas height specified.');}
|
|
|
|
var retval = {
|
|
canvas: {
|
|
width: ("width" in param.canvas) ? param.canvas.width : 200 ,
|
|
height: ("width" in param.canvas) ? param.canvas.height : 200 ,
|
|
exportTo: ("exportTo" in param.canvas) ? param.canvas.exportTo : [],
|
|
stretch: ("stretch" in param.canvas) ? param.canvas.stretch : true
|
|
},
|
|
graph: {
|
|
ringColor :("ringColor" in param.graph) ? param.graph.ringColor : '#74cc84',
|
|
labelColor :("labelColor" in param.graph) ? param.graph.labelColor : 'red',
|
|
diameter : ("diameter" in param.graph) ? param.graph.diameter : 200,
|
|
gapWidth :("gapWidth" in param.graph) ? param.graph.gapWidth :50,
|
|
useShadows: ("useShadows" in param.graph) ? param.graph.useShadows : false,
|
|
allowTransition: ("allowTransition" in param.graph) ? param.graph.allowTransition : false,
|
|
allowZoom: ("allowZoom" in param.graph) ? param.graph.allowZoom : false
|
|
}
|
|
};
|
|
return retval;
|
|
}
|
|
function createDefaultParamsForGraphVelocimeter(param) {
|
|
|
|
if (param.canvas == null) {throw new Error('You need specify canvas configuration parameters.');}
|
|
if (param.graph == null) {throw new Error('You need specify graph configuration parameters.');}
|
|
if (param.canvas.width == null) {throw new Error('No canvas width specified.');}
|
|
if (param.canvas.height == null) {throw new Error('No canvas height specified.');}
|
|
|
|
var retval = {
|
|
canvas: {
|
|
width: ("width" in param.canvas) ? param.canvas.width : 700 ,
|
|
height: ("width" in param.canvas) ? param.canvas.height : 200 ,
|
|
exportTo: ("exportTo" in param.canvas) ? param.canvas.exportTo : [],
|
|
stretch: ("stretch" in param.canvas) ? param.canvas.stretch : true
|
|
},
|
|
graph: {
|
|
useShadows: ("useShadows" in param.graph) ? param.graph.useShadows : false,
|
|
allowZoom: ("allowZoom" in param.graph) ? param.graph.allowZoom : false
|
|
}
|
|
};
|
|
return retval;
|
|
}
|
|
function createDefaultParamsForGraphPie(param) {
|
|
if (param.canvas == null) {throw new Error('You need specify canvas configuration parameters.');}
|
|
if (param.graph == null) {throw new Error('You need specify graph configuration parameters.');}
|
|
if (param.canvas.width == null) {throw new Error('No canvas width specified.');}
|
|
if (param.canvas.height == null) {throw new Error('No canvas height specified.');}
|
|
|
|
//if (param.graph.axisX == null) {param.graph.axisX = { showAxis: true, label: "X" };}
|
|
//if (param.graph.axisY == null) {param.graph.axisX = { showAxis: true, label: "Y" };}
|
|
|
|
|
|
|
|
var retval = {
|
|
canvas: {
|
|
width: ("width" in param.canvas) ? param.canvas.width : 100 ,
|
|
height: ("height" in param.canvas) ? param.canvas.height : 100 ,
|
|
exportTo: ("exportTo" in param.canvas) ? param.canvas.exportTo : [],
|
|
stretch: ("stretch" in param.canvas) ? param.canvas.stretch : true
|
|
},
|
|
graph: {
|
|
allowTransition: ("allowTransition" in param.graph) ? param.graph.allowTransition : false,
|
|
//axisX: ("axisX" in param.graph) ? param.graph.axisX : false,
|
|
//axisY: ("axisY" in param.graph) ? param.graph.axisY : false,
|
|
allowDrillDown: ("allowDrillDown" in param.graph) ? param.graph.allowDrillDown : false,
|
|
allowZoom: ("allowZoom" in param.graph) ? param.graph.allowZoom : false,
|
|
useShadows: ("useShadows" in param.graph) ? param.graph.useShadows : false,
|
|
showTip: ("showTip" in param.graph) ? param.graph.showTip : false,
|
|
thickness: ("thickness" in param.graph) ? param.graph.thickness : 50,
|
|
showLabels: ("showLabels" in param.graph) ? param.graph.showLabels : false,
|
|
colorPalette: ("colorPalette" in param.graph) ? param.graph.colorPalette : ["#62C1A3", "#FB906B", "#8DA1CB", "#E88AC2", "#E4C18F", "#B3B3B3", "#3180BA", "#50B14D", "#9A51A4", "#F87709", "#A35920","#A6D954", "#FED92F", "#ED2617"]
|
|
}
|
|
//linesx: true,
|
|
//linesy: true
|
|
};
|
|
return retval;
|
|
}
|
|
function createDefaultParamsForLineChart(param) {
|
|
var graphParam = {
|
|
axisX: ("axisX" in param) ? defaultAxis(param.axisX) : defaultAxis({}),
|
|
axisY: ("axisY" in param) ? defaultAxis(param.axisY) : defaultAxis({})
|
|
};
|
|
addValueForProperty(graphParam, param, 'allowTransition', false);
|
|
addValueForProperty(graphParam, param, 'allowZoom', false);
|
|
addValueForProperty(graphParam, param, 'useShadows', false);
|
|
addValueForProperty(graphParam, param, 'showTip', false);
|
|
addValueForProperty(graphParam, param, 'paddingTop', 0);
|
|
addValueForProperty(graphParam, param, 'area', { visible: false, css: "area"});
|
|
addValueForProperty(graphParam, param, 'marker', { visible: true, ratio: 5, css: "default"});
|
|
addValueForProperty(graphParam, param, 'line', { visible: true, css: "line1"});
|
|
addValueForProperty(graphParam, param, 'gridLinesX', true);
|
|
addValueForProperty(graphParam, param, 'gridLinesY', true);
|
|
addValueForProperty(graphParam, param, 'showErrorBars', false);
|
|
return graphParam;
|
|
}
|
|
|
|
function stretchCanvas(canvas, $container, params) {
|
|
if (params.canvas.stretch) {
|
|
if ($container.width() == null || $container.height() == null) {
|
|
throw new Error('stretchCanvas: The container ' + $container.attr('id') + ' must have a width and height assigned.')
|
|
}
|
|
var widthToUse = ($container.width() == null || $container.width() == 0) ? params.canvas.width : $container.width();
|
|
var heightToUse = ($container.height() == null || $container.height() == 0) ? params.canvas.height : $container.height();
|
|
|
|
|
|
|
|
//for ring
|
|
var diameterToUse = d3.min([widthToUse, heightToUse],
|
|
function (d) {return d;}
|
|
);
|
|
params.canvas.width = widthToUse;
|
|
params.canvas.height = heightToUse;
|
|
params.graph.diameter = diameterToUse;
|
|
}
|
|
|
|
//TODO a better way is to stretch using SVG native functions. The following code does not work correctly
|
|
/*canvas.attr('width', '100%')
|
|
.attr('height', '98%')
|
|
.attr("viewBox", "0 0 " + .$container.width()+ " " + $containr.height())
|
|
.attr("preserveAspectRatio", "xMidYMid meet")
|
|
.attr("pointer-events", "all");*/
|
|
|
|
if (canvas == null) {
|
|
return;
|
|
}
|
|
canvas.attr('width', '100%')
|
|
.attr('height', '98%')
|
|
.attr("viewBox", "0 0 " + widthToUse+ " " + heightToUse)
|
|
.attr("preserveAspectRatio", "xMidYMid meet")
|
|
.attr("pointer-events", "all");
|
|
return canvas;
|
|
}
|
|
|
|
function redrawChart(chart) {
|
|
chart.attr("transform",
|
|
"translate(" + d3.event.translate + ")"
|
|
+ " scale(" + d3.event.scale + ")");
|
|
}
|
|
|
|
function createCanvas (selectorId, param) {
|
|
d3.select('#'+selectorId).select('svg').remove();
|
|
var canvas = d3.select('#'+selectorId)
|
|
.append('svg')
|
|
.attr('width', param.width)
|
|
.attr('height', param.height);
|
|
return canvas;
|
|
}
|
|
|
|
function addZoomToCanvas(canvas) {
|
|
/*canvas.call(d3.behavior.zoom().on("zoom", function () {
|
|
canvas.attr("transform",
|
|
"translate(" + d3.event.translate + ")"
|
|
+ " scale(" + d3.event.scale + ")");
|
|
}));*/
|
|
var zoom = d3.behavior.zoom()
|
|
.scaleExtent([1, 3])
|
|
.on("zoom", function(){
|
|
canvas.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
|
|
});
|
|
canvas.call(zoom);
|
|
|
|
}
|
|
|
|
function addExportOptions(container, exportOptions) {
|
|
var arr = [];
|
|
$(exportOptions).each (function() {
|
|
arr.push({val:this.toLowerCase(), text: this})
|
|
});
|
|
|
|
/*var arr = [
|
|
{val : 'pdf', text: 'PDF'},
|
|
{val : 'png', text: 'PNG'},
|
|
{val : 'svg', text: 'SVG'}
|
|
];*/
|
|
|
|
var sel = $('<select>').appendTo(container);
|
|
sel.append($("<option>").attr('value','').text('Export To ...'));
|
|
|
|
$(arr).each(function() {
|
|
sel.append($("<option>").attr('value',this.val).text(this.text));
|
|
});
|
|
|
|
sel.css({
|
|
'position': 'absolute',
|
|
'top' : 0,
|
|
'left' : 0
|
|
})
|
|
|
|
sel.change(function() {
|
|
var exportType = this.options[this.selectedIndex].value;
|
|
var svgElement = container.get(0).getElementsByTagName('svg')[0];
|
|
var svgSerialized = (new XMLSerializer)
|
|
.serializeToString(svgElement);
|
|
|
|
var form = document.getElementById("svgform");
|
|
form['output_format'].value = exportType;
|
|
form['data'].value = svgSerialized ;
|
|
form.submit();
|
|
|
|
/*var newForm = jQuery('<form>', {
|
|
'action': 'http://d3export.housegordon.org/download.pl',
|
|
'method': 'post',
|
|
'target': '_top'
|
|
})
|
|
|
|
newForm.append(jQuery('<input>', {
|
|
'name': 'output_format',
|
|
'value': exportType,
|
|
'type': 'hidden'
|
|
}));
|
|
|
|
newForm.append(jQuery('<input>', {
|
|
'name': 'data',
|
|
'value': svgSerialized,
|
|
'type': 'hidden'
|
|
}));
|
|
|
|
newForm.get(0).submit();*/
|
|
});
|
|
container.append(sel);
|
|
}
|
|
|
|
function addDefsSection(canvas) {
|
|
var defs = canvas.select('defs');
|
|
if (defs.empty()) {
|
|
defs = canvas.append('defs');
|
|
}
|
|
return defs;
|
|
}
|
|
|
|
function addGradient(canvas, gradientId) {
|
|
|
|
defs = addDefsSection (canvas);
|
|
|
|
var gradient = defs.append("linearGradient")
|
|
.attr("id", gradientId)
|
|
.attr("y1", 10)
|
|
.attr("y2", 800)
|
|
.attr("x1", "0")
|
|
.attr("x2", "0")
|
|
.attr("gradientUnits", "userSpaceOnUse");
|
|
|
|
gradient.append("stop")
|
|
.attr("offset", "0")
|
|
.attr("stop-color", "#99d5cf")
|
|
|
|
gradient.append("stop")
|
|
.attr("offset", "0.5")
|
|
.attr("stop-color", "#009688")
|
|
}
|
|
|
|
function linesX(data,selector,parameter){
|
|
|
|
var width = parameter.width;
|
|
var svg = d3.select('#'+selector+' svg');
|
|
|
|
var arra = [],
|
|
lens;
|
|
for (key in data) {
|
|
arra.push(key);
|
|
}
|
|
lens = arra.length;
|
|
var barLabelsx = data.map(function(data){
|
|
return data.datalabel;
|
|
});
|
|
|
|
var sx = d3.scale.ordinal().domain(barLabelsx).rangePoints([50, width-50]);
|
|
|
|
function make_x_axis() {
|
|
return d3.svg.axis()
|
|
.scale(sx)
|
|
.orient("bottom")
|
|
.ticks(lens)
|
|
}
|
|
|
|
var group3 = svg.append("g");
|
|
group3.append("g")
|
|
.attr("class", "grid")
|
|
.attr("transform", "translate(0," + 240 + ")")
|
|
.call(make_x_axis()
|
|
.tickSize(-220, 0, 0)
|
|
.tickFormat("")
|
|
);
|
|
}
|
|
|
|
function linesY(data, selector, parameter){
|
|
|
|
}
|
|
/*
|
|
function addToolTip(canvas) {
|
|
var div = d3.select("body")
|
|
.append("div")
|
|
.attr("class", "tooltipdiv")
|
|
.style("opacity", 0)
|
|
.style("width","auto")
|
|
.style("height","auto");
|
|
return div;
|
|
}*/
|
|
|
|
|
|
/*function addToolTip(canvas, template) {
|
|
if (template === undefined) {
|
|
var template = "<strong>Value:</strong> <span style='color:orange'>%value%</span><br><strong>Datalabel:</strong> <span style='color:orange'>%datalabel%</span>";
|
|
}
|
|
var tip = d3.tip()
|
|
.attr('class', 'd3-tip')
|
|
.offset([-10, 0])
|
|
.html(function(d) {
|
|
var replacements = {'%value%' : d.value, '%datalabel%' : d.datalabel};
|
|
return template.replace(/%\w+%/g, function(all) { return replacements[all] || all; });
|
|
});
|
|
canvas.call(tip);
|
|
return tip;
|
|
}*/
|
|
|
|
function addToolTipPie(canvas) {
|
|
|
|
var tip = d3.tip()
|
|
.attr('class', 'd3-tip')
|
|
.offset([-10, 0])
|
|
.html(function(d) {
|
|
return "<strong>Value:</strong> <span style='color:#57B1DB'>"+d.data.value+"</span><br><strong>Data Label:</strong> <span style='color:#57B1DB'>"+d.data.label+"</span>";
|
|
});
|
|
canvas.call(tip);
|
|
return tip;
|
|
}
|
|
|
|
function addToolTipPie2D(canvas, stretch) {
|
|
|
|
var tip = d3.tip()
|
|
.attr('class', 'd3-tip')
|
|
.offset(function () {
|
|
if(stretch) { return [240,0] }
|
|
else { return [0,0] }
|
|
})
|
|
.html(function(d,i) {
|
|
return "<strong>Value:</strong> <span style='color:#57B1DB'>"+d.value+"</span><br><strong>Data Label:</strong> <span style='color:#57B1DB'>"+d.data.cat+"</span>";
|
|
});
|
|
canvas.call(tip);
|
|
return tip;
|
|
}
|
|
|
|
|
|
function addShadow(canvas, shadowHeightPercent, shadowWidth)
|
|
{
|
|
var defs = addDefsSection (canvas);
|
|
|
|
var filter = defs.append("filter")
|
|
.attr("id", "drop-shadow")
|
|
.attr("height", shadowHeightPercent);
|
|
|
|
// SourceAlpha refers to opacity of graphic that this filter will be applied to
|
|
// convolve that with a Gaussian with standard deviation 3 and store result
|
|
// in blur
|
|
filter.append("feGaussianBlur")
|
|
.attr("in", "SourceAlpha")
|
|
.attr("stdDeviation", shadowWidth)
|
|
.attr("result", "blur");
|
|
|
|
// translate output of Gaussian blur to the right and downwards with 2px
|
|
// store result in offsetBlur
|
|
filter.append("feOffset")
|
|
.attr("in", "blur")
|
|
.attr("dx", 1.5)
|
|
.attr("dy", 2)
|
|
.attr("result", "offsetBlur");
|
|
|
|
// overlay original SourceGraphic over translated blurred opacity by using
|
|
// feMerge filter. Order of specifying inputs is important!
|
|
var feMerge = filter.append("feMerge");
|
|
|
|
feMerge.append("feMergeNode")
|
|
.attr("in", "offsetBlur")
|
|
feMerge.append("feMergeNode")
|
|
.attr("in", "SourceGraphic");
|
|
}
|
|
|
|
|
|
function drawLinesX(data, chart, sx, parameter){
|
|
if (!parameter.graph.gridLinesX) return;
|
|
var DEFAULT_PADDING = 50;
|
|
var totalPaddingTop = DEFAULT_PADDING + parameter.graph.paddingTop;
|
|
var height = parameter.canvas.height - totalPaddingTop - DEFAULT_PADDING;
|
|
var width = parameter.canvas.width - 2 * DEFAULT_PADDING;
|
|
var chartRight = width + DEFAULT_PADDING;
|
|
var chartBottom = height + totalPaddingTop;
|
|
|
|
var arra = [],
|
|
lens;
|
|
for (key in data) {
|
|
arra.push(key);
|
|
}
|
|
lens = arra.length;
|
|
var barLabelsx = data.map(function(data){
|
|
return data.datalabel;
|
|
});
|
|
|
|
function make_x_axis() {
|
|
return d3.svg.axis()
|
|
.scale(sx)
|
|
.orient("bottom")
|
|
.ticks(parameter.graph.axisX.ticks)
|
|
}
|
|
|
|
var group3 = chart.append("g");
|
|
group3.append("g")
|
|
.attr("class", "grid")
|
|
.attr("transform", "translate(0,"+totalPaddingTop+")")
|
|
.call(make_x_axis()
|
|
.tickSize(height, 0, 0)
|
|
.tickFormat("")
|
|
);
|
|
}
|
|
|
|
function drawLinesY(data, chart, sy, parameter){
|
|
if (!parameter.graph.gridLinesY) return;
|
|
var DEFAULT_PADDING = 50;
|
|
var totalPaddingTop = DEFAULT_PADDING + parameter.graph.paddingTop;
|
|
var height = parameter.canvas.height - totalPaddingTop - DEFAULT_PADDING;
|
|
var width = parameter.canvas.width - 2 * DEFAULT_PADDING;
|
|
var chartRight = width + DEFAULT_PADDING;
|
|
var chartBottom = height + totalPaddingTop;
|
|
|
|
var maxValue = d3.max(data,function(d){ return d.value*1.0; });
|
|
/*var sy = d3.scale.linear().domain( [0,maxValue] ).range( [chartBottom,15] ).nice();*/
|
|
function make_y_axis() {
|
|
return d3.svg.axis()
|
|
.scale(sy)
|
|
.orient("left")
|
|
/*.attr('transform',function(d, i){
|
|
return "translate(0," + (i * 25 + 12) + ")"
|
|
})*/
|
|
.ticks(parameter.graph.axisY.ticks)
|
|
}
|
|
|
|
var group3 = chart.append("g");
|
|
group3.append("g")
|
|
.attr("class", "grid")
|
|
.attr("transform", "translate(" + DEFAULT_PADDING + ",0)")
|
|
.call(make_y_axis()
|
|
.tickSize(-width, 0, 0)
|
|
.tickFormat("")
|
|
);
|
|
}
|
|
|
|
function pushToStack(selectedDataPoint, graphObject) {
|
|
var objToAdd = {
|
|
previousDataPoint : selectedDataPoint,
|
|
graph : graphObject
|
|
}
|
|
graphObject.breadCrumbStack.push(objToAdd);
|
|
}
|
|
|
|
function refreshBreadCrumbs(graphObject) {
|
|
//if there is just one element do nothing.
|
|
if (graphObject.breadCrumbStack.length <= 1 ) {
|
|
return;
|
|
}
|
|
|
|
graphObject.$container.children('.graph-breadcrumb-div').remove();
|
|
graphObject.$container.append('<div class="graph-breadcrumb-div" style=" height:20px; padding-left:80px;border:1px solid;"></div>');
|
|
var breadCrumbsDiv = graphObject.$container.children('.graph-breadcrumb-div').first();
|
|
|
|
for (var i = 0; i < graphObject.breadCrumbStack.length; i++) {
|
|
var item = graphObject.breadCrumbStack[i];
|
|
var $newLink = $(document.createElement("a"));
|
|
$newLink.attr("class", "graph-breadcrumb-link");
|
|
$newLink.text((item.previousDataPoint == null)
|
|
? "init"
|
|
: item.previousDataPoint.datalabel);
|
|
$newLink.attr('href','#');
|
|
$newLink.attr('data-index', i);
|
|
|
|
$newLink.click(function() {
|
|
var index = $(this).data('index');
|
|
for (var i = index; i < graphObject.breadCrumbStack.length; i++) {
|
|
graphObject.breadCrumbStack.pop();
|
|
}
|
|
//getting array's last element
|
|
var element = graphObject.breadCrumbStack.slice(-1)[0];
|
|
element.graph.drawChart();
|
|
});
|
|
$newLink.appendTo(breadCrumbsDiv);
|
|
if (i < graphObject.breadCrumbStack.length -1) {
|
|
breadCrumbsDiv.append(" >> ");
|
|
}
|
|
}
|
|
}
|
|
|
|
//graph dimensions
|
|
var GraphDim = function (params) {
|
|
var DEFAULT_PADDING = 50;
|
|
this.top = DEFAULT_PADDING;
|
|
this.left = DEFAULT_PADDING;
|
|
this.height = params.canvas.height - 2 * DEFAULT_PADDING - 20;
|
|
this.width = params.canvas.width - 2 * DEFAULT_PADDING;
|
|
this.bottom = this.height + this.top;
|
|
this.right = this.width + this.left;
|
|
};
|
|
|
|
|
|
|
|
var LineChart = function (data, params, previousDataPoint, breadcrumbs) {
|
|
this.originalData = data;
|
|
this.previousDataPoint = previousDataPoint;
|
|
this.params = params;
|
|
this.$container = $('#' + this.params.canvas.containerId);
|
|
//Breadcrumb stack:
|
|
this.breadCrumbStack = (breadcrumbs == null ) ? [] : breadcrumbs;
|
|
pushToStack(previousDataPoint, this);
|
|
};
|
|
|
|
LineChart.prototype.drawChart = function() {
|
|
var $container = $('#' + this.params.canvas.containerId); // canvas[0] to convert d3 to jquery object
|
|
$container.empty();
|
|
$('.tooltipdiv').remove();
|
|
|
|
//TODO better if this is done inside the building function(drawLines)
|
|
stretchCanvas(null, this.$container, this.params);
|
|
|
|
this.canvas = createCanvas(this.params.canvas.containerId, this.params.canvas);
|
|
stretchCanvas(this.canvas, this.$container, this.params);
|
|
this.drawLines(this.originalData, this.canvas, this.params);
|
|
refreshBreadCrumbs(this);
|
|
};
|
|
|
|
LineChart.prototype.addTransitionToCircle = function(circle, ratio) {
|
|
circle.transition()
|
|
.duration(1000)
|
|
.attr({
|
|
r : ratio
|
|
});
|
|
};
|
|
|
|
LineChart.prototype.drawLines = function (data, canvas, param) {
|
|
if (data == null || data.length == 0) {
|
|
//this.$container.html( "<div class='pm-charts-no-draw'>No data to draw ...</div>" );
|
|
}
|
|
|
|
var parameter = createDefaultParamsForGraph(param);
|
|
//graph part of the parameters passed to this object
|
|
var graphParam = createDefaultParamsForLineChart(param.graph);
|
|
parameter.graph = graphParam;
|
|
|
|
//graph Dimensions inside the container
|
|
var graphDim = new GraphDim(param);
|
|
|
|
var tooltip = new ToolTip();
|
|
//HACK: to avoid context change in closure we store object's reference(this) here.
|
|
// JavaScript things...
|
|
var currObj = this;
|
|
|
|
|
|
var chart = canvas.append("g");
|
|
if (data == null || data.length == 0) {
|
|
canvas.append("text")
|
|
.attr('class','pm-charts-no-draw')
|
|
.attr("y", graphDim.height / 2)
|
|
.attr("x", graphDim.width/2)
|
|
.attr("dy", "1.5em")
|
|
.style("text-anchor", "end")
|
|
.text("No data to draw...");
|
|
data = [{"value":"0", "datalabel":"None"}];
|
|
}
|
|
|
|
var xScaleLabels = data.map(function(data){
|
|
return data.datalabel;
|
|
});
|
|
|
|
var maxValue = d3.max(data,function(d){ return d.value*1.0; });
|
|
|
|
var xScale = d3.scale
|
|
.ordinal()
|
|
.domain(xScaleLabels)
|
|
.rangePoints([graphDim.left, graphDim.right], 0);
|
|
|
|
var yScale = d3.scale
|
|
.linear()
|
|
.domain([0, maxValue])
|
|
.range([graphDim.bottom, graphDim.top]).nice();
|
|
|
|
drawAxisX(data, chart, xScale, parameter);
|
|
drawAxisY(data, chart, yScale, parameter);
|
|
drawLinesX(data, chart, xScale, parameter);
|
|
drawLinesY(data, chart, yScale, parameter);
|
|
|
|
var area = d3.svg.area()
|
|
.x(function(d) { return xScale(d.datalabel); })
|
|
.y0(graphDim.bottom)
|
|
.y1(function(d) { return yScale(d.value); });
|
|
|
|
var lineForValue = d3.svg.line()
|
|
.x(function(d) { return xScale(d.datalabel); })
|
|
.y(function(d) { return yScale(d.value); });
|
|
|
|
|
|
if (parameter.graph.allowZoom) { addZoomToCanvas(chart);}
|
|
|
|
data.forEach(function(d) {
|
|
d.value = +d.value;
|
|
});
|
|
|
|
var data0;
|
|
|
|
if (parameter.canvas.exportTo != null && parameter.canvas.exportTo.length > 0) {
|
|
addExportOptions($('#' + this.params.canvas.containerId), this.params.canvas.exportTo);
|
|
}
|
|
|
|
if (parameter.graph.allowTransition) {
|
|
data0 = data.map(function (d) { return {datalabel : d.datalabel, value : 0}; });
|
|
}
|
|
else {
|
|
data0 = data;
|
|
}
|
|
|
|
// Add the valueline path.
|
|
chart.append("path")
|
|
.attr("d", lineForValue(data0))
|
|
.attr("class", parameter.graph.line.css)
|
|
.transition()
|
|
.duration(3000)
|
|
.attr("d", lineForValue(data));
|
|
|
|
if (parameter.graph.area.visible) {
|
|
var pathArea = chart.append("path");
|
|
|
|
pathArea
|
|
.datum(data0)
|
|
.attr("class", parameter.graph.area.css)
|
|
.attr("d", area);
|
|
}
|
|
|
|
chart.selectAll("circle")
|
|
.data(data0)
|
|
.enter()
|
|
.append("circle")
|
|
.attr("class", parameter.graph.marker.css)
|
|
.each(function(d){
|
|
d3.select(this).attr({
|
|
cx: xScale(d.datalabel),
|
|
cy: yScale(d.value),
|
|
r: parameter.graph.marker.ratio
|
|
});
|
|
});
|
|
|
|
if (parameter.graph.showErrorBars) {
|
|
chart.selectAll(".errorBar")
|
|
.data (data0)
|
|
.enter()
|
|
.append("path")
|
|
.attr("class", "errorBar")
|
|
.each(function (d) {
|
|
var delta = d.dispersion / 2;
|
|
var xVal = xScale(d.datalabel);
|
|
var yVal0 = yScale(d.value - delta);
|
|
var yVal1 = yScale(d.value + delta);
|
|
d3.select(this)
|
|
.attr ("d", "M" + xVal + "," + yVal0
|
|
+ "L" + xVal + "," + yVal1);
|
|
|
|
});
|
|
|
|
chart.selectAll(".errorBarLowerMark")
|
|
.data (data0)
|
|
.enter()
|
|
.append("path")
|
|
.attr("class", "errorBarLowerMark")
|
|
.each(function (d) {
|
|
var delta = d.dispersion / 2;
|
|
var xVal = xScale(d.datalabel);
|
|
var yVal0 = yScale(d.value - delta);
|
|
var yVal1 = yScale(d.value + delta);
|
|
d3.select(this)
|
|
.attr ("d", "M" + (xVal - 5) + "," + yVal0
|
|
+ "L" + (xVal + 5) + "," + yVal0)
|
|
});
|
|
|
|
chart.selectAll(".errorBarUpperMark")
|
|
.data (data0)
|
|
.enter()
|
|
.append("path")
|
|
.attr("class", "errorBarUpperMark")
|
|
.each(function (d) {
|
|
var delta = d.dispersion / 2;
|
|
var xVal = xScale(d.datalabel);
|
|
var yVal0 = yScale(d.value - delta);
|
|
var yVal1 = yScale(d.value + delta);
|
|
d3.select(this)
|
|
.attr ("d", "M" + (xVal - 5) + "," + yVal1
|
|
+ "L" + (xVal + 5) + "," + yVal1)
|
|
});
|
|
|
|
}
|
|
|
|
if (parameter.graph.allowTransition) {
|
|
if (parameter.graph.area.visible) {
|
|
pathArea
|
|
.datum(data)
|
|
.transition()
|
|
.duration(3000)
|
|
.attr("d", area);
|
|
}
|
|
|
|
chart.selectAll("circle")
|
|
.data(data)
|
|
.each(function(d){
|
|
d3.select(this)
|
|
.transition()
|
|
.duration(3000)
|
|
.attr('class', parameter.graph.marker.css)
|
|
.attr({
|
|
cx: xScale(d.datalabel),
|
|
cy: yScale(d.value)
|
|
});
|
|
});
|
|
}
|
|
|
|
//colocamos este código después de la transición para asegurarnos
|
|
//que se usan los datos correctos.
|
|
if (parameter.graph.showTip) {
|
|
chart.selectAll('circle')
|
|
.data(data)
|
|
.on('mouseover', function (d) {
|
|
tooltip.show(function () {
|
|
if (parameter.graph.showErrorBars)
|
|
return {value: d.value + ' (sdv = ' + d.dispersion + ')', datalabel: d.datalabel}
|
|
else
|
|
return {value: d.value, datalabel: d.datalabel}
|
|
});
|
|
currObj.addTransitionToCircle(d3.select(this), parameter.graph.marker.ratio);
|
|
})
|
|
.on('mouseout', function () {
|
|
currObj.addTransitionToCircle(d3.select(this), parameter.graph.marker.ratio);
|
|
if(parameter.graph.showTip) {
|
|
tooltip.hide();
|
|
}
|
|
})
|
|
}
|
|
|
|
if (this.params.graph.allowDrillDown) {
|
|
this.addOnClick(data, canvas);
|
|
if (this.breadCrumbStack.length > 0) {
|
|
var clip = chart.append("defs")
|
|
.append("svg:clipPath")
|
|
.attr("id", "clip")
|
|
.append("svg:rect")
|
|
.attr("id", "clip-rect")
|
|
.attr("x", "0")
|
|
.attr("y", "0")
|
|
.attr("width", 50)
|
|
.attr("height", 50)
|
|
.transition()
|
|
.duration(2000)
|
|
.attr("width", 500)
|
|
.attr("height", 500);
|
|
d3.select("svg g").attr('clip-path', 'url(#clip)');
|
|
}
|
|
}
|
|
};
|
|
|
|
//function used to implement the drill-down
|
|
LineChart.prototype.addOnClick = function (arrayData, canvas) {
|
|
//HACK: to avoid context change in closue we store object's reference(this) here.
|
|
// JavaScript things...
|
|
var currObj = this;
|
|
canvas.selectAll("circle")
|
|
.data(arrayData)
|
|
.on("click", function (pointData) {
|
|
if (pointData.callBack != null && pointData.callBack.length != '') {
|
|
var $container = $(canvas[0]).parent();
|
|
$container.empty();
|
|
$('.d3-tip').remove();
|
|
var funCallBack = eval(pointData.callBack);
|
|
funCallBack(pointData, currObj);
|
|
}
|
|
});
|
|
};
|
|
|
|
|
|
var PieChart = function (data, params, previousDataPoint, breadcrumbs) {
|
|
this.originalData = data;
|
|
this.previousDataPoint = previousDataPoint;
|
|
this.params = params;
|
|
this.$container = $('#' + this.params.canvas.containerId);
|
|
//Breadcrumb stack:
|
|
this.breadCrumbStack = (breadcrumbs == null ) ? [] : breadcrumbs;
|
|
pushToStack(previousDataPoint, this);
|
|
};
|
|
|
|
PieChart.prototype.drawChart = function () {
|
|
var $container = $('#' + this.params.canvas.containerId); // canvas[0] to convert d3 to jquery object
|
|
$container.empty();
|
|
$('.tooltipdiv').remove();
|
|
|
|
//TODO better if this is done inside the building function(drawLines)
|
|
stretchCanvas(null, this.$container, this.params);
|
|
|
|
this.canvas = createCanvas(this.params.canvas.containerId, this.params.canvas);
|
|
this.drawPie2D(this.originalData, this.canvas, this.params);
|
|
refreshBreadCrumbs(this);
|
|
};
|
|
|
|
PieChart.prototype.drawPie2D = function (dataset, canvas, param) {
|
|
if (dataset == null || dataset.length == 0) {
|
|
this.$container.html( "<div class='pm-charts-no-draw'>No data to draw ...</div>" );
|
|
}
|
|
|
|
var parameter = createDefaultParamsForGraphPie(param);
|
|
var width = parameter.canvas.width,
|
|
height = parameter.canvas.height;
|
|
|
|
var tooltip = new ToolTip();
|
|
|
|
if (parameter.graph.showLabels) {
|
|
height = height - 50;
|
|
width = width - 150;
|
|
}
|
|
|
|
var margin = 50,
|
|
radius = Math.min(width - margin, height - margin) / 2,
|
|
// Pie layout will use the "val" property of each data object entry
|
|
pieChart = d3.layout.pie().sort(null).value(function (d) {
|
|
return d.value;
|
|
}),
|
|
arc = d3.svg.arc().outerRadius(radius);
|
|
var colors2 = parameter.graph.colorPalette;
|
|
|
|
|
|
// Synthetic data generation ------------------------------------------------
|
|
var data = Data(dataset);
|
|
|
|
function Data(data) {
|
|
return data.map(function (d, i) {
|
|
var newcolor;
|
|
if (i == parameter.graph.colorPalette.length) {
|
|
newcolor = "#000000";
|
|
} else {
|
|
newcolor = colors2[i % parameter.graph.colorPalette.length];
|
|
}
|
|
var children = [];
|
|
var color = colors2[i];
|
|
/* children.push({
|
|
datalabel: "datalabel" + ((i + 1) * 100 + i),
|
|
value: Math.random(),
|
|
color: d3.rgb(color).darker(1 / (i + 1))
|
|
});*/
|
|
return {
|
|
datalabel: (d.datalabel),
|
|
value: (d.value * 1),
|
|
//color: colors2[i%(parameter.graph.colorPalette.length-1)],
|
|
color: newcolor,
|
|
children: children,
|
|
callBack: d.callBack
|
|
};
|
|
});
|
|
}
|
|
|
|
var totalValues = 0;
|
|
|
|
|
|
for (var i = 0; i < data.length; i++) {
|
|
totalValues = totalValues + data[i].value;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// SVG elements init
|
|
//var svg = d3.select("body").append("svg").attr("width", width).attr("height", height),
|
|
var chart = canvas.append('g');
|
|
var svg = chart,
|
|
defs = svg.append("svg:defs"),
|
|
// Declare a main gradient with the dimensions for all gradient entries to refer
|
|
mainGrad = defs.append("svg:radialGradient")
|
|
.attr("gradientUnits", "userSpaceOnUse")
|
|
.attr("cx", 0).attr("cy", 0).attr("r", radius).attr("fx", 0).attr("fy", 0)
|
|
.attr("id", "master")
|
|
// The pie sectors container
|
|
arcGroup = svg.append("svg:g")
|
|
.attr("class", "arcGroup")
|
|
//.attr("filter", "url(#shadow)")
|
|
.attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")"),
|
|
// Header text
|
|
header = svg.append("text").text("")
|
|
.attr("transform", "translate(10, 20)").attr("class", "header");
|
|
|
|
|
|
if (parameter.graph.allowZoom) {
|
|
addZoomToCanvas(chart);
|
|
}
|
|
|
|
|
|
// Redraw the graph given a certain level of data
|
|
|
|
function updateGraph(currObject, datalabel) {
|
|
var currData = data;
|
|
|
|
// Simple header text
|
|
if (datalabel != undefined) {
|
|
currData = findChildenByCat(datalabel);
|
|
d3.select(".header").text("");
|
|
} else {
|
|
d3.select(".header").text("");
|
|
}
|
|
|
|
// Create a gradient for each entry (each entry identified by its unique category)
|
|
var gradients = defs.selectAll(".gradient").data(currData, function (d) {
|
|
return d.datalabel;
|
|
});
|
|
gradients.enter().append("svg:radialGradient")
|
|
.attr("id", function (d, i) {
|
|
return "gradient" + i;
|
|
})
|
|
.attr("class", "gradient")
|
|
.attr("xlink:href", "#master");
|
|
|
|
gradients.append("svg:stop").attr("offset", "0%").attr("stop-color", getColor);
|
|
gradients.append("svg:stop").attr("offset", "90%").attr("stop-color", getColor);
|
|
gradients.append("svg:stop").attr("offset", "100%").attr("stop-color", getDarkerColor);
|
|
|
|
|
|
// Create a sector for each entry in the enter selection
|
|
var paths = arcGroup.selectAll("path")
|
|
.data(pieChart(currData), function (d) {
|
|
return d.data.datalabel;
|
|
});
|
|
|
|
paths.enter().append("svg:path").attr("class", "sector");
|
|
|
|
|
|
if (currObject.params.graph.allowDrillDown) {
|
|
currObject.addOnClick(data, paths, canvas);
|
|
if (currObject.breadCrumbStack.length > 0) {
|
|
var clip = chart.append("defs")
|
|
.append("svg:clipPath")
|
|
.attr("id", "clip")
|
|
.append("svg:rect")
|
|
.attr("id", "clip-rect")
|
|
.attr("x", "0")
|
|
.attr("y", "0")
|
|
.attr("width", 50)
|
|
.attr("height", 50)
|
|
.transition()
|
|
.duration(2000)
|
|
.attr("width", 500)
|
|
.attr("height", 500);
|
|
d3.select("svg g").attr('clip-path', 'url(#clip)');
|
|
}
|
|
}
|
|
|
|
// Each sector will refer to its gradient fill
|
|
paths.attr("fill", function (d, i) {
|
|
return "url(#gradient" + i + ")";
|
|
})
|
|
.transition().duration(1000).attrTween("d", tweenIn).each("end", function () {
|
|
this._listenToEvents = true;
|
|
});
|
|
|
|
// Mouse interaction handling
|
|
/*
|
|
paths.on("click", function(d){
|
|
if(this._listenToEvents){
|
|
// Reset inmediatelly
|
|
d3.select(this).attr("transform", "translate(0,0)")
|
|
// Change level on click if no transition has started
|
|
paths.each(function(){
|
|
this._listenToEvents = false;
|
|
});
|
|
updateGraph(d.data.children? d.data.datalabel : undefined);
|
|
}
|
|
})
|
|
*/
|
|
paths.on("mouseover", function (d) {
|
|
// Mouseover effect if no transition has started
|
|
if (this._listenToEvents) {
|
|
// Calculate angle bisector
|
|
var ang = d.startAngle + (d.endAngle - d.startAngle) / 2;
|
|
// Transformate to SVG space
|
|
ang = (ang - (Math.PI / 2)) * -1;
|
|
|
|
// Calculate a 10% radius displacement
|
|
var x = Math.cos(ang) * radius * 0.1;
|
|
var y = Math.sin(ang) * radius * -0.1;
|
|
|
|
d3.select(this).transition()
|
|
.duration(250).attr("transform", "translate(" + x + "," + y + ")");
|
|
}
|
|
|
|
if (parameter.graph.showTip) {
|
|
tooltip.show(function () {
|
|
return {
|
|
value: d.value,
|
|
datalabel: d.data.datalabel
|
|
}
|
|
});
|
|
}
|
|
})
|
|
.on("mouseout", function (d) {
|
|
// Mouseout effect if no transition has started
|
|
if (this._listenToEvents) {
|
|
d3.select(this).transition()
|
|
.duration(150).attr("transform", "translate(0,0)");
|
|
}
|
|
if (parameter.graph.showTip) {
|
|
tooltip.hide();
|
|
}
|
|
});
|
|
|
|
// Collapse sectors for the exit selection
|
|
paths.exit().transition()
|
|
.duration(1000)
|
|
.attrTween("d", tweenOut).remove();
|
|
}
|
|
|
|
// "Fold" pie sectors by tweening its current start/end angles
|
|
// into 2*PI
|
|
function tweenOut(data) {
|
|
data.startAngle = data.endAngle = (2 * Math.PI);
|
|
var interpolation = d3.interpolate(this._current, data);
|
|
this._current = interpolation(0);
|
|
return function (t) {
|
|
return arc(interpolation(t));
|
|
};
|
|
}
|
|
|
|
|
|
// "Unfold" pie sectors by tweening its start/end angles
|
|
// from 0 into their final calculated values
|
|
function tweenIn(data) {
|
|
var interpolation = d3.interpolate({
|
|
startAngle: 0,
|
|
endAngle: 0
|
|
}, data);
|
|
this._current = interpolation(0);
|
|
return function (t) {
|
|
return arc(interpolation(t));
|
|
};
|
|
}
|
|
|
|
|
|
// Helper function to extract color from data object
|
|
function getColor(data, index) {
|
|
return data.color;
|
|
}
|
|
|
|
|
|
// Helper function to extract a darker version of the color
|
|
function getDarkerColor(data, index) {
|
|
return d3.rgb(getColor(data, index)).darker(0.7);
|
|
}
|
|
|
|
|
|
function findChildenByCat(datalabel) {
|
|
for (i = -1; i++ < data.length - 1;) {
|
|
if (data[i].datalabel == datalabel) {
|
|
return data[i].children;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
function getPercent(d) {
|
|
|
|
return (Math.round(100 * d / totalValues * 10) / 10 + '%');
|
|
}
|
|
|
|
// Start by updating graph at root level
|
|
updateGraph(this);
|
|
|
|
if (parameter.graph.showLabels) {
|
|
var thickness = 119 * Math.log(parameter.canvas.height) - 645;
|
|
var group5 = chart.append("g")
|
|
.attr("class", "group5")
|
|
.attr("transform", "translate(0," + thickness + ")");
|
|
for (var i = 0; i < data.length; i++) {
|
|
var newcolor;
|
|
if (i == parameter.graph.colorPalette.length) {
|
|
newcolor = "#000000";
|
|
} else {
|
|
newcolor = colors2[i % parameter.graph.colorPalette.length];
|
|
}
|
|
group5.append("circle")
|
|
.attr("r", 9)
|
|
.attr("fill", newcolor)
|
|
.attr("cx", width)
|
|
.attr("cy", (i * 25));
|
|
}
|
|
|
|
group5.selectAll("text")
|
|
.data(data)
|
|
.enter()
|
|
.append("text")
|
|
.attr("x", width + 30)
|
|
.attr("class", "legend")
|
|
.text(function (d, i) {
|
|
return (d.datalabel + "-" + getPercent(d.value))
|
|
})
|
|
.attr("transform", function (d, i) {
|
|
return "translate(0," + (i * 25 + 5) + ")"
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
//function used to implement the drill-down
|
|
PieChart.prototype.addOnClick = function (arrayData, paths, canvas) {
|
|
//HACK: to avoid context change in closue we store object's reference(this) here.
|
|
// JavaScript things...
|
|
var currObj = this;
|
|
//paths.enter().append("svg:path").attr("class", "sector");
|
|
//canvas.selectAll("path.sector")
|
|
paths.on("click", function (pieData) {
|
|
//piedData has the data encapsulated inside the data property.
|
|
var pointData = pieData.data;
|
|
if (pointData.callBack != null && pointData.callBack.length != '') {
|
|
var $container = $(canvas[0]).parent();
|
|
$container.empty();
|
|
$('.tooltipdiv').remove();
|
|
var funCallBack = eval(pointData.callBack);
|
|
funCallBack(pointData, currObj);
|
|
}
|
|
});
|
|
};
|
|
|
|
var Pie3DChart = function (data, params, previousDataPoint, breadcrumbs) {
|
|
this.originalData = data;
|
|
this.previousDataPoint = previousDataPoint;
|
|
this.params = params;
|
|
this.$container = $('#' + this.params.canvas.containerId);
|
|
//Breadcrumb stack:
|
|
this.breadCrumbStack = (breadcrumbs == null ) ? [] : breadcrumbs;
|
|
pushToStack(previousDataPoint, this);
|
|
};
|
|
|
|
Pie3DChart.prototype.drawChart = function () {
|
|
var $container = $('#' + this.params.canvas.containerId); // canvas[0] to convert d3 to jquery object
|
|
$container.empty();
|
|
$('.tooltipdiv').remove();
|
|
|
|
//TODO better if this is done inside the building function(drawLines)
|
|
stretchCanvas(null, this.$container, this.params);
|
|
|
|
this.canvas = createCanvas(this.params.canvas.containerId, this.params.canvas);
|
|
this.drawPie3D(this.originalData, this.canvas, this.params);
|
|
refreshBreadCrumbs(this);
|
|
};
|
|
|
|
|
|
Pie3DChart.prototype.drawPie3D = function (data, canvas, param) {
|
|
|
|
if (data == null || data.length == 0) {
|
|
this.$container.html( "<div class='pm-charts-no-draw'>No data to draw ...</div>" );
|
|
}
|
|
|
|
var duration_transition = 0;
|
|
var parameter = createDefaultParamsForGraphPie(param);
|
|
var totalValues = 0;
|
|
var h = parameter.canvas.height,
|
|
w = parameter.canvas.width
|
|
|
|
for (var i = 0; i < data.length; i++) {
|
|
totalValues = totalValues + data[i].value * 1;
|
|
}
|
|
|
|
if (parameter.graph.showLabels) {
|
|
h = h - 50;
|
|
w = w - 150;
|
|
}
|
|
|
|
var x_center = w / 2;
|
|
var y_center = (h / 2 - 50);
|
|
var rx = w / 2 - parameter.graph.thickness;
|
|
var ry = h / 2 / 2;
|
|
|
|
var color = parameter.graph.colorPalette;
|
|
var chart = canvas.append('g')
|
|
.attr("transform", "translate(0,0)");
|
|
|
|
var group4 = chart.append("g")
|
|
.attr("class", "group4")
|
|
.attr("id", "salesDonut")
|
|
.attr("transform", "translate(7,0)");
|
|
|
|
if (parameter.graph.allowTransition) {
|
|
var duration_transition = 100;
|
|
}
|
|
|
|
var tooltip = null;
|
|
if (parameter.graph.showTip) {
|
|
tooltip = new ToolTip();
|
|
}
|
|
|
|
|
|
Donut3D.draw("salesDonut", Data(), x_center, y_center, rx, ry, param.graph.thickness,
|
|
param.graph.gapWidth, duration_transition,
|
|
tooltip, parameter, canvas, this);
|
|
|
|
|
|
|
|
function getPercent(d) {
|
|
return (Math.round(100 * d / totalValues * 10) / 10 + '%');
|
|
}
|
|
|
|
function Data() {
|
|
return data.map(function (d, i) {
|
|
var newcolor;
|
|
if (i == parameter.graph.colorPalette.length) {
|
|
newcolor = "#000000";
|
|
} else {
|
|
newcolor = color[i % parameter.graph.colorPalette.length];
|
|
}
|
|
return {
|
|
label: (d.datalabel),
|
|
datalabel: (d.datalabel),
|
|
value: (d.value * 1),
|
|
callBack: d.callBack,
|
|
//color: (color[i%(parameter.graph.colorPalette.length)])
|
|
color: newcolor
|
|
};
|
|
});
|
|
}
|
|
|
|
|
|
if (parameter.graph.allowZoom) {
|
|
addZoomToCanvas(chart);
|
|
}
|
|
|
|
if (parameter.graph.showLabels) {
|
|
|
|
var thickness = 119 * Math.log(parameter.canvas.height) - 645;
|
|
|
|
var group5 = chart.append("g")
|
|
.attr("class", "group5")
|
|
.attr("transform", "translate(0," + thickness + ")");
|
|
|
|
for (var i = 0; i < data.length; i++) {
|
|
var newcolor;
|
|
if (i == parameter.graph.colorPalette.length) {
|
|
newcolor = "#000000";
|
|
} else {
|
|
newcolor = color[i % parameter.graph.colorPalette.length];
|
|
}
|
|
group5.append("circle")
|
|
.attr("r", 9)
|
|
//.attr("height", 15)
|
|
.attr("fill", newcolor)
|
|
.attr("cx", w)
|
|
.attr("cy", (i * 25));
|
|
//.attr("transform", "translate("+param.canvas.width+"," + (i * 25) + ")");
|
|
}
|
|
|
|
group5.selectAll("text")
|
|
.data(data)
|
|
.enter()
|
|
.append("text")
|
|
.attr("x", w + 30)
|
|
.attr("class", "legend")
|
|
//.attr("y",i*10+50)
|
|
.text(function (d, i) {
|
|
return d.datalabel + " - " + getPercent(d.value * 1)
|
|
})
|
|
.on("mouseover", function (d, i) {
|
|
d3.select("#salesDonut")
|
|
.select(".topSlice" + i)
|
|
.style("fill", d3.hsl("#E87886").darker(0.8))
|
|
.style("stroke", d3.hsl("#E87886").darker(0.8));
|
|
})
|
|
.on("mouseout", function (d, i) {
|
|
|
|
var newcolor;
|
|
if (i == parameter.graph.colorPalette.length) {
|
|
newcolor = "#000000";
|
|
} else {
|
|
newcolor = color[i % parameter.graph.colorPalette.length];
|
|
}
|
|
|
|
d3.select("#salesDonut")
|
|
.select(".topSlice" + i)
|
|
.style("fill", d3.hsl(newcolor))
|
|
.style("stroke", d3.hsl(newcolor));
|
|
})
|
|
.attr("transform", function (d, i) {
|
|
return "translate(0," + (i * 25 + 5) + ")"
|
|
});
|
|
|
|
}
|
|
|
|
|
|
if (parameter.graph.useShadows) {
|
|
addShadow(group4, "130%", 5);
|
|
group4.select('.slices')
|
|
.attr("filter", "url(#drop-shadow)");
|
|
}
|
|
}
|
|
|
|
|
|
var RingChart = function (data, params, previousDataPoint, breadcrumbs) {
|
|
this.originalData = data;
|
|
this.previousDataPoint = previousDataPoint;
|
|
this.params = params;
|
|
this.$container = $('#' + this.params.canvas.containerId);
|
|
//Breadcrumb stack:
|
|
this.breadCrumbStack = (breadcrumbs == null ) ? [] : breadcrumbs;
|
|
pushToStack(previousDataPoint, this);
|
|
};
|
|
|
|
RingChart.prototype.drawChart = function () {
|
|
var $container = $('#' + this.params.canvas.containerId); // canvas[0] to convert d3 to jquery object
|
|
$container.empty();
|
|
$('.tooltipdiv').remove();
|
|
|
|
//TODO better if this is done inside the building function(drawLines)
|
|
stretchCanvas(null, this.$container, this.params);
|
|
|
|
this.canvas = createCanvas(this.params.canvas.containerId, this.params.canvas);
|
|
this.drawRing(this.originalData, this.canvas, this.params);
|
|
refreshBreadCrumbs(this);
|
|
};
|
|
|
|
RingChart.prototype.drawRing = function(data, canvas, param){
|
|
if (data == null || data.length == 0) {
|
|
this.$container.html( "<div class='pm-charts-no-draw'>No data to draw ...</div>" );
|
|
}
|
|
|
|
//d3.select('#'+parent).select('svg').remove();
|
|
var parameter = createDefaultParamsForGraphRign(param);
|
|
var h = parameter.canvas.height,
|
|
w = parameter.canvas.width;
|
|
var value = data[0].value;
|
|
var ringColor = parameter.graph.ringColor;
|
|
var labelColor = parameter.graph.labelColor;
|
|
var label = data[0].datalabel;
|
|
var diameter1 = parameter.graph.diameter;
|
|
|
|
var currObject = this;
|
|
|
|
if (parameter.graph.allowZoom) { addZoomToCanvas(canvas); }
|
|
|
|
var rp1 = radialProgress(canvas)
|
|
//alert(diameter);
|
|
.label(label)
|
|
//.onClick(onClick1)
|
|
.diameter(diameter1)
|
|
.value(value)
|
|
.render();
|
|
|
|
function radialProgress(canvas) {
|
|
var _data=null,
|
|
_duration= 0,
|
|
_selection,
|
|
_margin = {top:20, right:0, bottom:30, left:20},
|
|
__width = parameter.graph.diameter,
|
|
__height = parameter.graph.diameter,
|
|
_diameter,
|
|
_label="",
|
|
_fontSize=10;
|
|
|
|
if(parameter.graph.allowTransition){_duration= 1000;}
|
|
|
|
|
|
var _mouseClick;
|
|
|
|
var _value= 0,
|
|
_minValue = 0,
|
|
_maxValue = 100;
|
|
|
|
var _currentArc= 0, _currentArc2= 0, _currentValue=0;
|
|
|
|
var _arc = d3.svg.arc()
|
|
.startAngle(0 * (Math.PI/180)); //just radians
|
|
|
|
var _arc2 = d3.svg.arc()
|
|
.startAngle(0 * (Math.PI/180))
|
|
.endAngle(0); //just radians
|
|
|
|
|
|
_selection=canvas;
|
|
|
|
|
|
function component() {
|
|
|
|
_selection.each(function (data) {
|
|
|
|
// Select the svg element, if it exists.
|
|
var svg = d3.select(this).selectAll("svg").data([data]);
|
|
var enter = svg.enter().append("svg").attr("class","radial-svg").append("g");
|
|
|
|
measure();
|
|
|
|
/*if (parameter.graph.useShadows){
|
|
addShadow(enter, "130%", 2);
|
|
}*/
|
|
|
|
svg.attr("width", __width)
|
|
.attr("height", __height);
|
|
|
|
|
|
var background = enter.append("g").attr("class","component")
|
|
.attr("cursor","pointer");
|
|
//.on("click",onMouseClick);
|
|
|
|
|
|
_arc.endAngle(360 * (Math.PI/180))
|
|
|
|
background.append("rect")
|
|
.attr("class","background")
|
|
.attr("width", _width)
|
|
.attr("height", _height);
|
|
|
|
background.append("path")
|
|
.attr("transform", "translate(" + _width/2 + "," + _width/2 + ")")
|
|
.attr("d", _arc);
|
|
|
|
if (currObject.params.graph.showLabel) {
|
|
background.append("text")
|
|
.attr("class", "label")
|
|
.attr("transform", "translate(" + _width/2 + "," + (_height + 25) + ")")
|
|
.attr("fill", labelColor)
|
|
.text(_label);
|
|
}
|
|
|
|
|
|
var g = svg.select("g")
|
|
.attr("transform", "translate(" + _margin.left + "," + _margin.top + ")");
|
|
|
|
|
|
_arc.endAngle(_currentArc);
|
|
enter.append("g").attr("class", "arcs");
|
|
var path = svg.select(".arcs").selectAll(".arc").data(data);
|
|
path.enter().append("path")
|
|
.attr("class","arc")
|
|
.attr("fill", ringColor)
|
|
//.style("filter", "url(#drop-shadow-ring)")
|
|
.attr("transform", "translate(" + _width/2 + "," + _width/2 + ")")
|
|
.attr("d", _arc)
|
|
.on ('click', function (){
|
|
if (currObject.params.graph.allowDrillDown) {
|
|
var pointData = currObject.originalData[0];
|
|
if (pointData.callBack != null && pointData.callBack.length != '') {
|
|
var $container = $(canvas[0]).parent();
|
|
$container.empty();
|
|
$('.tooltipdiv').remove();
|
|
var funCallBack = eval(pointData.callBack);
|
|
funCallBack(pointData, currObject);
|
|
}
|
|
|
|
if (currObject.breadCrumbStack.length > 0) {
|
|
var clip = canvas.append("defs")
|
|
.append("svg:clipPath")
|
|
.attr("id", "clip")
|
|
.append("svg:rect")
|
|
.attr("id", "clip-rect")
|
|
.attr("x", "0")
|
|
.attr("y", "0")
|
|
.attr("width", 50)
|
|
.attr("height", 50)
|
|
.transition()
|
|
.duration(2000)
|
|
.attr("width", 500)
|
|
.attr("height", 500);
|
|
d3.select("svg g").attr('clip-path', 'url(#clip)');
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
|
|
//Another path in case we exceed 100%
|
|
var path2 = svg.select(".arcs").selectAll(".arc2").data(data);
|
|
path2.enter().append("path")
|
|
.attr("class","arc2")
|
|
//.style("filter", "url(#drop-shadow)")
|
|
.attr("transform", "translate(" + _width/2 + "," + _width/2 + ")")
|
|
.attr("d", _arc2);
|
|
|
|
|
|
enter.append("g").attr("class", "labels");
|
|
var label = svg.select(".labels").selectAll(".label").data(data);
|
|
label.enter().append("text")
|
|
.attr("class","label")
|
|
.attr("y",_width/2+_fontSize/3)
|
|
.attr("x",_width/2)
|
|
.attr("cursor","pointer")
|
|
.attr("width",_width)
|
|
// .attr("x",(3*_fontSize/2))
|
|
.text(function (d) { return Math.round((_value-_minValue)/(_maxValue-_minValue)*100) + "%" })
|
|
.style("font-size",_fontSize+"px")
|
|
.on("click",onMouseClick);
|
|
|
|
|
|
if(parameter.graph.useShadows)
|
|
{
|
|
addShadow(enter, "150%", 5);
|
|
|
|
//----------------------From Internet Explorer 10
|
|
var path1 = svg.selectAll('.arc')
|
|
.attr("filter", "url(#drop-shadow)");
|
|
//svg.select(".labels").selectAll('.label')
|
|
//.style("text-shadow", "5px 4px 4px black");
|
|
//---------------------------------------------End
|
|
}
|
|
|
|
|
|
path.exit().transition().duration(500).attr("x",1000).remove();
|
|
|
|
|
|
layout(svg);
|
|
|
|
function layout(svg) {
|
|
|
|
var ratio=(_value-_minValue)/(_maxValue-_minValue);
|
|
var endAngle=Math.min(360*ratio,360);
|
|
endAngle=endAngle * Math.PI/180;
|
|
|
|
path.datum(endAngle);
|
|
path.transition().duration(_duration)
|
|
.attrTween("d", arcTween);
|
|
|
|
if (ratio > 1) {
|
|
path2.datum(Math.min(360*(ratio-1),360) * Math.PI/180);
|
|
path2.transition().delay(_duration).duration(_duration)
|
|
.attrTween("d", arcTween2);
|
|
}
|
|
|
|
label.datum(Math.round(ratio*100));
|
|
label.transition().duration(_duration)
|
|
.tween("text",labelTween);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
function onMouseClick(d) {
|
|
if (typeof _mouseClick == "function") {
|
|
//DL: original call back function commented
|
|
//_mouseClick.call();
|
|
}
|
|
}
|
|
}
|
|
|
|
function labelTween(a) {
|
|
var i = d3.interpolate(_currentValue, a);
|
|
_currentValue = i(0);
|
|
|
|
return function(t) {
|
|
_currentValue = i(t);
|
|
this.textContent = Math.round(i(t)) + "%";
|
|
}
|
|
}
|
|
|
|
function arcTween(a) {
|
|
var i = d3.interpolate(_currentArc, a);
|
|
|
|
return function(t) {
|
|
_currentArc=i(t);
|
|
return _arc.endAngle(i(t))();
|
|
};
|
|
}
|
|
|
|
function arcTween2(a) {
|
|
var i = d3.interpolate(_currentArc2, a);
|
|
|
|
return function(t) {
|
|
return _arc2.endAngle(i(t))();
|
|
};
|
|
}
|
|
|
|
|
|
function measure() {
|
|
_width=_diameter - _margin.right - _margin.left - _margin.top - _margin.bottom;
|
|
//_width = _diameter;
|
|
_height=_width;
|
|
_fontSize=_width*.2;
|
|
_arc.outerRadius(_width/2);
|
|
_arc.innerRadius(_width/2 * (parameter.graph.gapWidth/100));
|
|
_arc2.outerRadius(_width/2 * .85);
|
|
_arc2.innerRadius(_width/2 * .85 - (_width/2 * .15));
|
|
}
|
|
|
|
|
|
component.render = function() {
|
|
measure();
|
|
component();
|
|
return component;
|
|
}
|
|
|
|
component.value = function (_) {
|
|
if (!arguments.length) return _value;
|
|
_value = [_];
|
|
_selection.datum([_value]);
|
|
return component;
|
|
}
|
|
|
|
|
|
component.margin = function(_) {
|
|
if (!arguments.length) return _margin;
|
|
_margin = _;
|
|
return component;
|
|
};
|
|
|
|
component.diameter = function(_) {
|
|
if (!arguments.length) return _diameter
|
|
_diameter = _;
|
|
return component;
|
|
};
|
|
|
|
component.minValue = function(_) {
|
|
if (!arguments.length) return _minValue;
|
|
_minValue = _;
|
|
return component;
|
|
};
|
|
|
|
component.maxValue = function(_) {
|
|
if (!arguments.length) return _maxValue;
|
|
_maxValue = _;
|
|
return component;
|
|
};
|
|
|
|
component.label = function(_) {
|
|
if (!arguments.length) return _label;
|
|
_label = _;
|
|
return component;
|
|
};
|
|
|
|
component._duration = function(_) {
|
|
if (!arguments.length) return _duration;
|
|
_duration = _;
|
|
return component;
|
|
};
|
|
|
|
component.onClick = function (_) {
|
|
if (!arguments.length) return _mouseClick;
|
|
_mouseClick=_;
|
|
return component;
|
|
}
|
|
|
|
return component;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
var ToolTip = function (template) {
|
|
this.template = template;
|
|
if (template == null) {
|
|
this.template = "<strong>Value: </strong><span style='color:orange'>%value%</span><br/><strong>Data Label: </strong><span style='color:orange'>%datalabel%</span>";
|
|
}
|
|
this.div = d3.select("body")
|
|
.append("div")
|
|
.attr("class", "tooltipdiv")
|
|
.style("opacity", 0)
|
|
.style("width","auto")
|
|
.style("height","auto");
|
|
}
|
|
|
|
ToolTip.prototype.show = function (funPointData) {
|
|
var replacements = {'%value%' : funPointData().value, '%datalabel%' : funPointData().datalabel};
|
|
var tipHtml = this.template.replace(/%\w+%/g, function(all) { return replacements[all] || all;});
|
|
|
|
this.div
|
|
.transition()
|
|
.duration(200)
|
|
.style("opacity", .9);
|
|
|
|
this.div
|
|
.html(tipHtml)
|
|
.style("left", (d3.event.pageX-50) + "px")
|
|
.style("top", (d3.event.pageY-55) + "px");
|
|
}
|
|
|
|
ToolTip.prototype.hide = function (){
|
|
this.div
|
|
.transition()
|
|
.duration(500)
|
|
.style("opacity", 0);
|
|
}
|
|
|
|
|
|
|
|
function drawVelocimeter(selector,param){
|
|
window.onload=function(){
|
|
|
|
var gauges = [];
|
|
//var dashContainer;
|
|
var readings = []; // pretend readings are supplied (named by gauge).
|
|
var i = 0;
|
|
var interv0 = 0;
|
|
var xDim = 0;
|
|
|
|
var greenColor = "#107618";
|
|
var yellowColor = "#FFC900";
|
|
var redColor = "#EC4922";
|
|
var darkColor = "#101010";
|
|
var blueColor = "#1030B0";
|
|
var dimBlueColor = "#101560";
|
|
var lightColor = "#EEEEEE";
|
|
var greyColor = "303030";
|
|
var darkGreyColor = "101010";
|
|
var blackColor = "000000";
|
|
var lightBlueColor = "7095F0";
|
|
|
|
//InitDim();
|
|
createDashboard(selector, param);
|
|
//interv0 = setInterval(updateGauges, 1000); // set a basic interval period
|
|
|
|
function createDashboard(selector, param) {
|
|
createDash(selector, param);
|
|
createGauge(dashContainer, 25, "inbox", "Inbox", 72, 145,90, {
|
|
from: 0, to: 25 }, {
|
|
from: 25, to: 50 }, {
|
|
from: 50, to: 100});
|
|
createGauge(dashContainer, 50, "cases", "Cases", 72, 505,90, {// third is +size bias.
|
|
from: 0, to: 25 }, {
|
|
from: 25, to: 50 }, {
|
|
from: 50, to: 100});
|
|
createGauge(dashContainer, 100, "drafts", "Drafts", 72, 860,90, {
|
|
from: 0, to: 25 }, {
|
|
from: 25, to: 50 }, {
|
|
from: 50, to: 100});
|
|
}
|
|
|
|
function updateGauges() {
|
|
if (i >= 0) { // initially use a faster interval and sweep the gauge
|
|
{
|
|
for (var key in gauges) {
|
|
gauges[key].redraw(i);
|
|
}
|
|
if (i === 0) {
|
|
clearInterval(interv0);
|
|
interv0 = setInterval(updateGauges, 75);
|
|
}
|
|
i = i + 5;
|
|
if (i > 100) {
|
|
i = -1;
|
|
clearInterval(interv0);
|
|
interv0 = setInterval(updateGauges, 1000); // restore a normal interval
|
|
}
|
|
}
|
|
} else {
|
|
// pass a data array to dashboard.js's UpdateDashboard(values for named gauges)
|
|
for (var key in gauges) {
|
|
readings[key] = readings[key] + 10*Math.random()-5;
|
|
if (readings[key]<0)
|
|
readings[key] = 0;
|
|
if (readings[key]>100)
|
|
readings[key] = 100;
|
|
gauges[key].redraw(readings[key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// code below here could go in a dashboard.js
|
|
|
|
function dimChange() {
|
|
dimDash(this.selectedIndex);
|
|
for (var key in gauges) {
|
|
gauges[key].dimDisplay(this.selectedIndex); // just use the index; could use the indexed entry value.
|
|
}
|
|
}
|
|
|
|
function InitDim() {
|
|
var dimOptions = { "Day": 0, "Night": 1 };
|
|
|
|
var selectUI = d3.select("#dimmable").append("form").append("select").on("change", dimChange);
|
|
selectUI.selectAll("option").data(d3.keys(dimOptions)).enter().append("option").text(function (d) { return d; });
|
|
|
|
selectUI.selectAll("option").data(d3.values(dimOptions)).attr("value", function (d) { return d; });
|
|
|
|
var checkOption = function (e) {
|
|
if (e === xDim) { return d3.select(this).attr("selected", "selected"); }
|
|
};
|
|
|
|
selectUI.selectAll("option").each(checkOption);
|
|
}
|
|
|
|
// some of createGauge is specific to the example (size=120), some belongs in Gauge.
|
|
function createDash(selector, param)
|
|
{
|
|
if (param.canvas.stretch) {
|
|
this.body = d3.select("#"+selector)
|
|
.append("svg:svg")
|
|
.attr('width', '100%')
|
|
.attr('height', '98%')
|
|
.attr("viewBox", "0 0 " + param.canvas.width + " " + 180)
|
|
.attr("preserveAspectRatio", "xMidYMid meet")
|
|
.attr("pointer-events", "all");
|
|
|
|
}else{
|
|
this.body = d3.select("#"+selector)
|
|
.append("svg:svg")
|
|
.attr("class", "dash")
|
|
.attr("width", param.canvas.width)//this.config.size)
|
|
.attr("height", param.canvas.height);// this.config.size);
|
|
}
|
|
|
|
dashContainer = this.body.append("svg:g").attr("class", "dashContainer")
|
|
.attr("width",404)
|
|
.attr("height",202);
|
|
|
|
if (param.graph.allowZoom) {
|
|
addZoomToCanvas(dashContainer);
|
|
}
|
|
}
|
|
|
|
function dimDash(value) {
|
|
var dasharea =d3.select("#dashboardContainer").selectAll("ellipse");
|
|
dasharea.style("fill",value<0.5 ? blueColor: dimBlueColor);
|
|
}
|
|
|
|
function createGauge(myContainer, value, name, label, sizebias, containerOffsetx, containerOffsety, redZone, yellowZone, greenZone) {
|
|
var config = {
|
|
size: 120 + sizebias,
|
|
cx: containerOffsetx,
|
|
cy: containerOffsety,
|
|
label: label,
|
|
minorTicks: 5
|
|
};
|
|
|
|
config.redZones = []; // allows for example upper and lower limit zones
|
|
config.redZones.push(redZone);
|
|
|
|
config.yellowZones = [];
|
|
config.yellowZones.push(yellowZone);
|
|
|
|
config.greenZones = [];
|
|
config.greenZones.push(greenZone);
|
|
|
|
gauges[name] = new Gauge(myContainer, name, config,value);
|
|
gauges[name].render();
|
|
readings[name] = 50;
|
|
}
|
|
|
|
// code from gauge.js, below
|
|
//
|
|
function Gauge(myContainer, name, configuration, value) {
|
|
this.name = name;
|
|
this.myContainer = myContainer;
|
|
|
|
var self = this; // some internal d3 functions do not "like" the "this" keyword, hence setting a local variable
|
|
|
|
this.configure = function (configuration) {
|
|
this.config = configuration;
|
|
|
|
this.config.size = this.config.size * 0.9;
|
|
|
|
this.config.raduis = this.config.size * 0.97 / 2;
|
|
this.config.cx = this.config.cx;// + this.config.size / 4;
|
|
this.config.cy = this.config.cy;// + this.config.size / 2;
|
|
|
|
this.config.min = configuration.min || 0;
|
|
this.config.max = configuration.max || 100;
|
|
this.config.range = this.config.max - this.config.min;
|
|
|
|
this.config.majorTicks = configuration.majorTicks || 5;
|
|
this.config.minorTicks = configuration.minorTicks || 2;
|
|
|
|
this.config.bezelColor = configuration.bezelColor || lightColor;
|
|
this.config.bezelDimColor = configuration.bezelDimColor || greyColor;
|
|
this.config.greenColor = configuration.greenColor || greenColor;
|
|
this.config.yellowColor = configuration.yellowColor || yellowColor;
|
|
this.config.redColor = configuration.redColor || redColor;
|
|
this.config.faceColor = configuration.faceColor || lightColor;
|
|
this.config.dimFaceColor = configuration.dimFaceColor || darkGreyColor;
|
|
this.config.lightColor = configuration.lightColor || "#EEEEEE";
|
|
this.config.greyColor = configuration.greyColor || "101010";
|
|
this.config.lightBlueColor = configuration.lightBlueColor || "6085A0";
|
|
|
|
};
|
|
|
|
this.render = function () {
|
|
this.body = this.myContainer//dashContainer//d3.select("#" + this.placeholderName)
|
|
.append("svg:svg")
|
|
.attr("class", "gauge")
|
|
.attr("x", this.myContainer.x)//this.config.cx-this.config.size/4)
|
|
.attr("y", this.myContainer.y)//this.config.cy-this.config.size/4)
|
|
.attr("width", this.myContainer.width)//this.config.size)
|
|
.attr("height", this.myContainer.height)//this.config.size);
|
|
|
|
this.body.append("svg:circle") // outer shell
|
|
.attr("cx", this.config.cx)
|
|
.attr("cy", this.config.cy)
|
|
.attr("r", this.config.raduis)
|
|
.style("fill", "#ccc")
|
|
.style("stroke", blackColor )
|
|
.style("stroke-width", "0.5px");
|
|
|
|
this.body.append("svg:circle") // bezel
|
|
.attr("cx", this.config.cx)
|
|
.attr("cy", this.config.cy)
|
|
.attr("r", 0.9 * this.config.raduis)
|
|
.style("fill", (xDim < 0.5 ? this.config.bezelColor : this.config.bezelDimColor))
|
|
.style("stroke", "#e0e0e0")
|
|
.style("stroke-width", "2px");
|
|
|
|
var faceContainer = this.body.append("svg:g").attr("class", "faceContainer"); // for day/night changes
|
|
var bandsContainer = this.body.append("svg:g").attr("class", "bandsContainer"); // for day/night changes
|
|
var ticksContainer = this.body.append("svg:g").attr("class", "ticksContainer"); // for day/night changes
|
|
this.redrawDimmableFace(xDim);//0);
|
|
|
|
var pointerContainer = this.body.append("svg:g").attr("class", "pointerContainer");
|
|
this.drawPointer(value);
|
|
pointerContainer.append("svg:circle")
|
|
.attr("cx", this.config.cx)
|
|
.attr("cy", this.config.cy)
|
|
.attr("r", 0.12 * this.config.raduis)
|
|
.style("fill", "#4684EE")
|
|
.style("stroke", "#666")
|
|
.style("opacity", 1);
|
|
};
|
|
|
|
this.drawBands = function(bandsContainer) {
|
|
for (var index in this.config.greenZones) {
|
|
this.drawBand(bandsContainer,this.config.greenZones[index].from, this.config.greenZones[index].to, self.config.greenColor);
|
|
}
|
|
|
|
for (var index in this.config.yellowZones) {
|
|
this.drawBand(bandsContainer,this.config.yellowZones[index].from, this.config.yellowZones[index].to, self.config.yellowColor);
|
|
}
|
|
|
|
for (var index in this.config.redZones) {
|
|
this.drawBand(bandsContainer,this.config.redZones[index].from, this.config.redZones[index].to, self.config.redColor);
|
|
}
|
|
};
|
|
|
|
this.redrawDimmableFace = function (value) {
|
|
this.drawFace(value < 0.5 ? self.config.faceColor : self.config.dimFaceColor, // facecolor
|
|
value < 0.5 ? self.config.greyColor : lightBlueColor);
|
|
}
|
|
|
|
this.drawTicks = function (ticksContainer,color) {
|
|
|
|
var fontSize = Math.round(this.config.size / 16);
|
|
var majorDelta = this.config.range / (this.config.majorTicks - 1);
|
|
for (var major = this.config.min; major <= this.config.max; major += majorDelta) {
|
|
var minorDelta = majorDelta / this.config.minorTicks;
|
|
for (var minor = major + minorDelta; minor < Math.min(major + majorDelta, this.config.max); minor += minorDelta) {
|
|
var minorpoint1 = this.valueToPoint(minor, 0.75);
|
|
var minorpoint2 = this.valueToPoint(minor, 0.85);
|
|
|
|
ticksContainer.append("svg:line")
|
|
.attr("x1", minorpoint1.x)
|
|
.attr("y1", minorpoint1.y)
|
|
.attr("x2", minorpoint2.x)
|
|
.attr("y2", minorpoint2.y)
|
|
.style("stroke", color)
|
|
.style("stroke-width", "1px");
|
|
}
|
|
|
|
var majorpoint1 = this.valueToPoint(major, 0.7);
|
|
var majorpoint2 = this.valueToPoint(major, 0.85);
|
|
|
|
ticksContainer.append("svg:line")
|
|
.attr("x1", majorpoint1.x)
|
|
.attr("y1", majorpoint1.y)
|
|
.attr("x2", majorpoint2.x)
|
|
.attr("y2", majorpoint2.y)
|
|
.style("stroke", color)
|
|
.style("stroke-width", "2px");
|
|
|
|
if (major == this.config.min || major == this.config.max) {
|
|
var point = this.valueToPoint(major, 0.63);
|
|
|
|
ticksContainer.append("svg:text")
|
|
.attr("x", point.x)
|
|
.attr("y", point.y)
|
|
.attr("dy", fontSize / 3)
|
|
.attr("text-anchor", major == this.config.min ? "start" : "end")
|
|
.text(major)
|
|
.style("font-size", fontSize + "px")
|
|
.style("fill", color)
|
|
.style("stroke-width", "0px");
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
this.redraw = function (value) {
|
|
this.drawPointer(value);
|
|
};
|
|
|
|
this.dimDisplay = function (value) {
|
|
this.redrawDimmableFace(value);
|
|
};
|
|
|
|
this.drawBand = function (bandsContainer, start, end, color) {
|
|
if (0 >= end - start) return;
|
|
|
|
bandsContainer.append("svg:path")
|
|
.style("fill", color)
|
|
.attr("d", d3.svg.arc()
|
|
.startAngle(this.valueToRadians(start))
|
|
.endAngle(this.valueToRadians(end))
|
|
.innerRadius(0.70 * this.config.raduis)
|
|
.outerRadius(0.85 * this.config.raduis))
|
|
.attr("transform", function () {
|
|
return "translate(" + self.config.cx + ", " + self.config.cy + ") rotate(270)";
|
|
});
|
|
};
|
|
|
|
this.drawFace = function (colorFace,colorTicks) {
|
|
var arc0 = d3.svg.arc()
|
|
.startAngle(0) //this.valueToRadians(0))
|
|
.endAngle(2 * Math.PI)
|
|
.innerRadius(0.00 * this.config.raduis)
|
|
.outerRadius(0.9 * this.config.raduis);
|
|
|
|
var faceContainer = this.body.selectAll(".faceContainer");
|
|
var bandsContainer = this.body.selectAll(".bandsContainer");
|
|
var ticksContainer = this.body.selectAll(".ticksContainer");
|
|
var pointerContainer = this.body.selectAll(".pointerContainer");
|
|
var face = faceContainer.selectAll("path");
|
|
if (face == 0)
|
|
{
|
|
faceContainer
|
|
.append("svg:path")
|
|
.attr("d", arc0) //d3.svg.arc()
|
|
.style("fill", colorFace)
|
|
.style("fill-opacity", 0.7)
|
|
.attr("transform",
|
|
"translate(" + self.config.cx + ", " + self.config.cy + ")");
|
|
|
|
this.drawBands(bandsContainer);
|
|
this.drawTicks(ticksContainer,colorTicks);
|
|
var fontSize = Math.round(this.config.size / 9);
|
|
faceContainer.append("svg:text")
|
|
.attr("x", this.config.cx)
|
|
.attr("y", this.config.cy - this.config.size/6 - fontSize / 2 )
|
|
.attr("dy", fontSize / 2)
|
|
.attr("text-anchor", "middle")
|
|
.text(this.config.label)
|
|
.style("font-size", fontSize + "px")
|
|
.style("fill", colorTicks)
|
|
.style("stroke-width", "0px");
|
|
}
|
|
else
|
|
{
|
|
face.style("fill", colorFace);
|
|
var facetxt = faceContainer.selectAll("text");
|
|
facetxt.style("fill", colorTicks);
|
|
var ptrtxt = pointerContainer.selectAll("text");
|
|
ptrtxt.style("fill", colorTicks);
|
|
var ticks = ticksContainer.selectAll("line");
|
|
ticks.style("stroke", colorTicks);
|
|
var texts = ticksContainer.selectAll("text");
|
|
texts.style("fill", colorTicks);
|
|
|
|
}
|
|
};
|
|
|
|
this.drawPointer = function (value) {
|
|
var delta = this.config.range / 13;
|
|
|
|
var head = this.valueToPoint(value, 0.85);
|
|
var head1 = this.valueToPoint(value - delta, 0.12);
|
|
var head2 = this.valueToPoint(value + delta, 0.12);
|
|
|
|
var tailValue = value - (this.config.range * (1 / (270 / 360)) / 2);
|
|
var tail = this.valueToPoint(tailValue, 0.28);
|
|
var tail1 = this.valueToPoint(tailValue - delta, 0.12);
|
|
var tail2 = this.valueToPoint(tailValue + delta, 0.12);
|
|
|
|
var data = [head, head1, tail2, tail, tail1, head2, head];
|
|
|
|
var line = d3.svg.line()
|
|
.x(function (d) {
|
|
return d.x;
|
|
})
|
|
.y(function (d) {
|
|
return d.y;
|
|
})
|
|
.interpolate("basis");
|
|
|
|
var pointerContainer = this.body.select(".pointerContainer");
|
|
|
|
var pointer = pointerContainer.selectAll("path").data([data]);
|
|
|
|
pointer.enter()
|
|
.append("svg:path")
|
|
.attr("d", line)
|
|
.style("fill", "#dc3912")
|
|
.style("stroke", "#c63310")
|
|
.style("fill-opacity", 0.7);
|
|
|
|
pointer.transition()
|
|
.attr("d", line)
|
|
//.ease("linear")
|
|
.duration(i>=0 ? 50 : 500);
|
|
|
|
var fontSize = Math.round(this.config.size / 10);
|
|
pointerContainer.selectAll("text")
|
|
.data([value])
|
|
.text(Math.round(value))
|
|
.enter()
|
|
.append("svg:text")
|
|
.attr("x", this.config.cx)
|
|
.attr("y", this.config.cy + this.config.size/6 + fontSize)
|
|
.attr("dy", fontSize / 2)
|
|
.attr("text-anchor", "middle")
|
|
.text(Math.round(value))
|
|
.style("font-size", fontSize + "px")
|
|
.style("fill", "#000")
|
|
.style("stroke-width", "0px");
|
|
};
|
|
|
|
this.valueToDegrees = function (value) {
|
|
return value / this.config.range * 270 - 45;
|
|
};
|
|
|
|
this.valueToRadians = function (value) {
|
|
return this.valueToDegrees(value) * Math.PI / 180;
|
|
};
|
|
|
|
this.valueToPoint = function (value, factor) {
|
|
var len = this.config.raduis * factor;
|
|
var inRadians = this.valueToRadians(value);
|
|
var point = {
|
|
x: this.config.cx - len * Math.cos(inRadians),
|
|
y: this.config.cy - len * Math.sin(inRadians)
|
|
};
|
|
|
|
return point;
|
|
};
|
|
|
|
// initialization
|
|
this.configure(configuration);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
!function(){
|
|
var Donut3D={};
|
|
|
|
function pieTop(d, rx, ry, ir ){
|
|
d.endAngle = d.endAngle - 0.001;
|
|
if(d.endAngle - d.startAngle == 0 ) return "M 0 0";
|
|
var sx = rx*Math.cos(d.startAngle),
|
|
sy = ry*Math.sin(d.startAngle),
|
|
ex = rx*Math.cos(d.endAngle),
|
|
ey = ry*Math.sin(d.endAngle);
|
|
|
|
var ret =[];
|
|
ret.push("M",sx,sy,"A",rx,ry,"0",(d.endAngle-d.startAngle > Math.PI? 1: 0),"1",ex,ey,"L",ir*ex,ir*ey);
|
|
ret.push("A",ir*rx,ir*ry,"0",(d.endAngle-d.startAngle > Math.PI? 1: 0), "0",ir*sx,ir*sy,"z");
|
|
return ret.join(" ");
|
|
}
|
|
|
|
function pieOuter(d, rx, ry, h ){
|
|
var startAngle = (d.startAngle > Math.PI ? Math.PI : d.startAngle);
|
|
var endAngle = (d.endAngle > Math.PI ? Math.PI : d.endAngle);
|
|
|
|
var sx = rx*Math.cos(startAngle),
|
|
sy = ry*Math.sin(startAngle),
|
|
ex = rx*Math.cos(endAngle),
|
|
ey = ry*Math.sin(endAngle);
|
|
|
|
var ret =[];
|
|
ret.push("M",sx,h+sy,"A",rx,ry,"0 0 1",ex,h+ey,"L",ex,ey,"A",rx,ry,"0 0 0",sx,sy,"z");
|
|
return ret.join(" ");
|
|
}
|
|
|
|
function pieInner(d, rx, ry, h, ir ){
|
|
var startAngle = (d.startAngle < Math.PI ? Math.PI : d.startAngle);
|
|
var endAngle = (d.endAngle < Math.PI ? Math.PI : d.endAngle);
|
|
|
|
var sx = ir*rx*Math.cos(startAngle),
|
|
sy = ir*ry*Math.sin(startAngle),
|
|
ex = ir*rx*Math.cos(endAngle),
|
|
ey = ir*ry*Math.sin(endAngle);
|
|
|
|
var ret =[];
|
|
ret.push("M",sx, sy,"A",ir*rx,ir*ry,"0 0 1",ex,ey, "L",ex,h+ey,"A",ir*rx, ir*ry,"0 0 0",sx,h+sy,"z");
|
|
return ret.join(" ");
|
|
}
|
|
|
|
function getPercent(d){
|
|
return (d.endAngle-d.startAngle > 0.2 ?
|
|
Math.round(1000*(d.endAngle-d.startAngle)/(Math.PI*2))/10+'%' : '');
|
|
}
|
|
|
|
Donut3D.transition = function(id, data, rx, ry, h, ir){
|
|
function arcTweenInner(a) {
|
|
var i = d3.interpolate(this._current, a);
|
|
this._current = i(0);
|
|
return function(t) { return pieInner(i(t), rx+0.5, ry+0.5, h, ir); };
|
|
}
|
|
function arcTweenTop(a) {
|
|
var i = d3.interpolate(this._current, a);
|
|
this._current = i(0);
|
|
return function(t) { return pieTop(i(t), rx, ry, ir); };
|
|
}
|
|
function arcTweenOuter(a) {
|
|
var i = d3.interpolate(this._current, a);
|
|
this._current = i(0);
|
|
return function(t) { return pieOuter(i(t), rx-.5, ry-.5, h); };
|
|
}
|
|
function textTweenX(a) {
|
|
var i = d3.interpolate(this._current, a);
|
|
this._current = i(0);
|
|
return function(t) { return 0.6*rx*Math.cos(0.5*(i(t).startAngle+i(t).endAngle)); };
|
|
}
|
|
function textTweenY(a) {
|
|
var i = d3.interpolate(this._current, a);
|
|
this._current = i(0);
|
|
return function(t) { return 0.6*rx*Math.sin(0.5*(i(t).startAngle+i(t).endAngle)); };
|
|
}
|
|
|
|
var _data = d3.layout.pie().sort(null).value(function(d) {return d.value;})(data);
|
|
|
|
d3.select("#"+id).selectAll(".innerSlice").data(_data)
|
|
.transition().duration(750).attrTween("d", arcTweenInner);
|
|
|
|
d3.select("#"+id).selectAll(".topSlice").data(_data)
|
|
.transition().duration(750).attrTween("d", arcTweenTop);
|
|
|
|
d3.select("#"+id).selectAll(".outerSlice").data(_data)
|
|
.transition().duration(750).attrTween("d", arcTweenOuter);
|
|
|
|
d3.select("#"+id).selectAll(".percent").data(_data).transition().duration(750)
|
|
.attrTween("x",textTweenX).attrTween("y",textTweenY).text(getPercent);
|
|
}
|
|
|
|
Donut3D.draw=function(id, data, x /*center x*/, y/*center y*/,
|
|
rx/*radius x*/, ry/*radius y*/, h/*height*/, ir/*inner radius*/, dt/*duration transition*/,
|
|
tip/*tooltip*/, parameter /*chart conf. parameters*/,
|
|
canvas /*place where the pie is drawn*/, currObj /*Pie3D object*/){
|
|
|
|
var _data = d3.layout.pie().sort(null).value(function(d) {return d.value;})(data);
|
|
|
|
var slices = d3.select("#"+id).append("g").attr("transform", "translate(" + x + "," + y + ")")
|
|
.attr("class", "slices");
|
|
|
|
slices.selectAll(".innerSlice").data(_data).enter().append("path")
|
|
.transition().delay(function(d, i) { return i * dt; }).duration(dt*5)
|
|
.attr("class", "innerSlice")
|
|
.style("fill", function(d) { return d3.hsl(d.data.color).darker(0.7); })
|
|
.attr("d",function(d){ return pieInner(d, rx+0.5,ry+0.5, h, ir);})
|
|
.each(function(d){this._current=d;});
|
|
|
|
//.on('mouseover', tip.show)
|
|
// .on('mouseout', tip.hide)
|
|
// TODO set tooltip here
|
|
slices.selectAll(".topSlice").data(_data).enter().append("path")
|
|
.on('mouseover', function (d) {
|
|
if (parameter.graph.showTip) {
|
|
tip.show(function () {
|
|
return {
|
|
value: d.data.value,
|
|
datalabel: d.data.datalabel
|
|
}
|
|
});
|
|
}
|
|
})
|
|
.on('mouseout', function () {
|
|
if (parameter.graph.showTip) {
|
|
tip.hide();
|
|
}
|
|
})
|
|
.on('click', function (d) {
|
|
if (parameter.graph.allowDrillDown) {
|
|
var pointData = d.data;
|
|
if (pointData.callBack != null && pointData.callBack.length != '') {
|
|
var $container = $(canvas[0]).parent();
|
|
$container.empty();
|
|
$('.tooltipdiv').remove();
|
|
var funCallBack = eval(pointData.callBack);
|
|
funCallBack(pointData, currObj);
|
|
}
|
|
}
|
|
})
|
|
.transition().delay(function(d, i) { return i * dt; }).duration(dt*5)
|
|
.attr("class", function(d,i){return "topSlice"+i})
|
|
.style("fill", function(d) { return d.data.color; })
|
|
.style("stroke", function(d) { return d.data.color; })
|
|
.attr("d",function(d){ return pieTop(d, rx, ry, ir);})
|
|
.each(function(d){this._current=d;});
|
|
|
|
slices.selectAll(".outerSlice").data(_data).enter().append("path")
|
|
.transition().delay(function(d, i) { return i * dt; }).duration(dt*5)
|
|
.attr("class", "outerSlice")
|
|
.style("fill", function(d) { return d3.hsl(d.data.color).darker(0.7); })
|
|
.attr("d",function(d){ return pieOuter(d, rx-.5,ry-.5, h);})
|
|
.each(function(d){this._current=d;});
|
|
|
|
slices.selectAll(".percent").data(_data).enter().append("text")
|
|
.transition().delay(function(d, i) { return i * dt; }).duration(dt*5)
|
|
.attr("class", "percent")
|
|
.attr("x",function(d){ return 0.6*rx*Math.cos(0.5*(d.startAngle+d.endAngle));})
|
|
.attr("y",function(d){ return 0.6*ry*Math.sin(0.5*(d.startAngle+d.endAngle));})
|
|
.text(getPercent).each(function(d){this._current=d;});
|
|
|
|
}
|
|
|
|
this.Donut3D = Donut3D;
|
|
}();
|
|
|