PortaleOrdiniGruppo/PortalStudio/chart/objects/ZtChartSunburst.js
2025-03-24 15:28:26 +01:00

603 lines
20 KiB
JavaScript

function ZtSunburstChart(type) {
StdChart.apply(this, [type, "e902"]);
this.multiSVG = true;
this.viewBreadcrumb = true;
this.breadcrumbPath = [];
this.byCount = (this.type == "SUNBSTR");
}
ZtSunburstChart.prototype = Object.create(ZtPieChart.prototype);
ZtSunburstChart.prototype.constructor = ZtSunburstChart;
ZtSunburstChart.prototype._SetChartSettingsJSON = function () {
this.defSettings.hierarchy = this.chartConfig.graphSettings.hierarchy;
this.defSettings.line = this.chartConfig.graphSettings.line;
this.viewBreadcrumb = this.defSettings.hierarchy.breadcrumb.show;
}
ZtSunburstChart.prototype._SetFieldsIndexes = function () {
this.yIndex = this.propertyName.indexOf(this.objConfig.valueFields);
this.levelsIndex = {};
var lev = this.objConfig.labelField.split(",");
for (var i = 0; i < lev.length; i++) {
this.levelsIndex[lev[i]] = this.propertyName.indexOf(lev[i]);
}
if (!Empty(this.objConfig.labelSeries))
this.levelsLabelFields = this.objConfig.labelSeries.split(",");
}
ZtSunburstChart.prototype._SetLists = function () {
this.levelsFields = this.objConfig.labelField.split(",");
this.valueFields = this.objConfig.valueFields;
this.orgCategoryList = this.categoryList = this.legendList = this.rowLegendList = this.orgSeriesList = this.seriesList = [];
this.drawingSeries = this.drawingCategories = [];
this.orgCategoryList = this.categoryList = getList(this.propertyName.indexOf(this.levelsFields[this.levelsFields.length - 1]), this.dataSet);
if(!Empty(this.calcDataset)) { //MG VPV //legendlist =[] implica che non disegna la legenda
this.orgSeriesList = getListFromObjectArray(this.calcDataset.children, "name").unique();
this.legendList = this.orgSeriesList.slice();
this.drawingSeries = this.orgSeriesList.slice();
}
}
ZtSunburstChart.prototype._SetCalculationDataset = function () {
var singleRoot = getList(this.levelsIndex[this.levelsFields[0]], this.dataSet).length == 1,
lSeries = !Empty(this.objConfig.labelSeries) ? this.objConfig.labelSeries : this.levelsFields[0],
addFields = [];
if (this.categoryCodeIndex >= 0)
addFields.push( { prop: "categoryCode", index: this.categoryCodeIndex } );
this.calcDataset = getHieDataset(this.dataSet, this.levelsFields, this.valueFields, lSeries, this.propertyName, addFields, singleRoot);
this._SetLists();
}
ZtSunburstChart.prototype._DrawChartPlot = function () {
this.CreateSVG(this.chartId, this.parent, true, 0, 0, this.defSettings.globals.width, this.defSettings.globals.height, true, this.chartWidth, this.chartHeight, this.margin.left, this.margin.top);// eslint-disable-line max-len
this.CreateRenderer(this.svg, this.chartId, this.chartWidth, this.chartHeight, this.margin.left, this.margin.top);
this._DrawChartPlotTitles(this.svg);
this.DrawBreadcrumb(this.svg);
}
ZtSunburstChart.prototype._DrawChartElements = function () {
var parentGroup = this.renderer.append("g")
.attr("id", this.chartId + this.type + "_svgGroup")
.attr("transform", "translate(" + [this.margin.left, this.margin.top] + ")");
var positions = this.GetRendererSubdivisionsSizes(this._GetDivisor()),
id = "",
group,
radius,
domainLabelH = 0,
slice = 7;
this._DrawPatterns();
this.totalValueLabel = {};
if (this.seriesList.length > 1)
domainLabelH = getOffsetHeight("W", this.defSettings.globalFont, this.chartId);
for (var i = 0; i < positions.length; i++) {
radius = Math.min(positions[i].width, positions[i].height) / 2;
radius = radius - domainLabelH;
radius = radius - radius * 0.05; // tolgo il 5% per dare un po' di spazio al disegno
radius = radius - ((radius * slice / 100) / 4);
this.radius = radius;
id = this.chartId + i + "_";
/*this.multiMargins[dList[i]] = { x : this.margin.left + positions[i].x,
y : this.margin.top + positions[i].y,
w : positions[i].width,
h : positions[i].height
};*/
this._DrawMultiSVGPlot(id, parentGroup, positions[i].x, positions[i].y, positions[i].width, positions[i].height);
group = this.renderer.append("g")
.attr("id", id + this.type + "_elementGroup")
.attr("transform","translate(" + [positions[i].width / 2, positions[i].height / 2] + ")");
this.DrawSunburst(group, this.calcDataset, i, id);
/* if (this.seriesList.length > 1)
this.DrawDomainLabel(i, positions[i], this.seriesList[this.valueFields.indexOf(dList[i])]);*/
}
this.svg = d3.select("#" + this.chartId + "d3ChartPlot");
this.renderer = d3.select("#" + this.chartId + "d3Renderer");
}
ZtSunburstChart.prototype._SetElementsColor = function () {
this.SetColorSet();
var idx = -1,
gradID,
colD,
colorsObj = [],
styleObj;
for (var i = 0; i < this.items.length; i++) {
idx = this.items[i].index;
if (idx >= 0) {
this.items[i].idx = idx;
if (this.items[i].depth <= 1) {
if( this.legendList && this.legendList.length > 0 ) {
if( idx == 0 ) {
this.items[i].color = this.colorSet[this.legendList.length];
}
else {
this.items[i].color = this.colorSet[idx-1];
}
}
else {
this.items[i].color = this.colorSet[idx];
}
colorsObj["_" + idx] = {
//lighter : getColorsArrayLighter(this.items[i].color.color, 7).reverse()
lighter : d3.interpolateRgb(d3.rgb(this.items[i].color.color), d3.rgb("#FFFFFF")),
}
}
else {
var parent = this._GetParent(this.items[i]);
if (parent) {
//this.items[i].color = colorsObj["_" + parent.index].lighter[this.items[i].depth - 1]
this.items[i].color = { color: colorsObj["_" + parent.index].lighter(this.items[i].depth / this._GetAnimatedDivisor()), gradient: "" }
}
}
styleObj = {};
gradID = this.chartId + this.type + "_" + idx + "Gradient";
if (!Empty(this.items[i].color.color) && Empty(this.items[i].color.gradient) || this.items[i].color.color.toLowerCase() == this.items[i].color.gradient.toLowerCase())
colD = this.items[i].color.color;
else if (Empty(this.items[i].color.color) && !Empty(this.items[i].color.gradient))
colD = this.items[i].color.gradient;
else {
this.CreateGradient(this.items[i].color.color, this.items[i].color.gradient, gradID, "element");
colD = "url(" + document.URL + "#" + gradID + ")";
}
styleObj.fill = colD;
if (this.items[i].depth == 0) {
if (!this.defSettings.hierarchy.showRoot)
styleObj.display = "none";
}
styleObj.stroke = this.defSettings.line.color || "";
styleObj.stroke9width = this.defSettings.line.stroke || 0;
d3.select(this.items[i].itm).attr("style", makeStyleHTMLString(styleObj, d3.select(this.items[i].itm).attr("style")));
}
}
}
ZtSunburstChart.prototype._GetDivisor = function () {
return this.valueFields.split(",").length;
}
ZtSunburstChart.prototype._GetParent = function (item) {
var parent = item.parent;
if (parent) {
var tpar = parent;
while (!Empty(parent.parent)) {
tpar = parent;
parent = parent.parent;
}
parent = tpar;
}
return parent;
}
ZtSunburstChart.prototype._GetChartMarginsObject = function (chartId, settings/*, categoryList, dataOrder, domainIsTime, domainIsNumber, localeLangFormat, datetimePict, chartLegends, allValues, valprec, domprec, excludedC, excludedS, defaultExcludedFont, rangebandslabels*/) { // eslint-disable-line max-len
var ret = {},
myM;
ret.top = [];
ret.bottom = [];
ret.left = [];
ret.right = [];
if (this.viewBreadcrumb) {
myM = setMarginObject("W", settings.globalFont, true, settings.globalFont);
if (myM != 0) {
myM.offset = 15; // 10 margine sopra e sotto altezza + 5 offset
ret.top.push(myM);
}
}
return ret;
}
ZtSunburstChart.prototype._ApplyMouseOver = function (item, itemObj, keepH) {
if (this.defSettings.hierarchy.hoverPath == "element" && !this.defSettings.hierarchy.breadcrumb.show)
return ZtPieChart.prototype._ApplyMouseOver.call(this, item, itemObj);
var idx = d3.select(item).attr("item-index"),
mRefChart = this._ZtChart.StdChart;
if (!keepH)
this.RemoveAllHovers();
var applyH = this.defSettings.hierarchy.hoverPath == "path" && keepH && !Empty(this.breadcrumbPath);
if (applyH || !keepH)
this.AppendHoverItem(item);
var itemObject = itemObj || this.items[idx];
if (!keepH)
this.ShowTooltip(mRefChart, item, itemObject);
var depthL = this.defSettings.hierarchy.showRoot ? 0 : 1;
if (itemObject.depth > depthL) {
var parent = itemObject.parent;
if (parent)
var parItem = this.items[parent.index];
if (this.breadcrumbPath.indexOf(itemObject.category + this.splitSequence + idx) < 0)
this.breadcrumbPath.push(itemObject.category + this.splitSequence + idx);
this._ApplyMouseOver(parItem.itm, null, true);
}
else if (item && this.viewBreadcrumb) {
// breadcrumb
if (this.breadcrumbPath.indexOf(itemObject.category + this.splitSequence + idx) < 0)
this.breadcrumbPath.push(itemObject.category + this.splitSequence + idx);
this.breadcrumbPath.reverse();
this.FillBreadcrumb(this.breadcrumbPath);
this.breadcrumbPath = [];
}
}
ZtSunburstChart.prototype.AppendHoverItem = function (item) {
var _this = this,
mRefChart = this._ZtChart.StdChart;
if (item) {
var itemObject = this._GetItems()[d3.select(item).attr("item-index")],
clone = this._GetItemClone(item, itemObject);
d3.select(clone)
.attr("item-type", "hover")
.style("opacity", 0.5)
.style("fill", function () {
if (!Empty(_this.defSettings.hoverColor))
return _this.defSettings.hoverColor;
var darkCol = d3.rgb(itemObject.colorApplied).darker().toString();
darkCol = d3.rgb(darkCol).darker().toString();
return d3.rgb(darkCol).darker().toString();
})
.style("cursor", function() {
if (!_this._ZtChart.enableClick)
return "default";
return "pointer";
})
.on("mousemove", function() {
mRefChart.ClearHoverTimeout();
})
.on("mouseout", function() {
_this.RemoveAllHovers();
// mRefChart.RemoveHoverTimeout();
})
.on("click", function () {
_this._ApplyClick(itemObject, d3.mouse(this));
});
item.parentNode.appendChild(clone);
this.MoveRangeCursor(itemObject.value);
}
}
ZtSunburstChart.prototype._DrawVLabelInside = function (group, items, font/*, valueField*/) {
var progrGrad,
text,
angleRad,
angleGrad,
radiusRot,
label,
radius,
maxH,
_this = this,
item;
var x = d3.scaleLinear().range([0, 2 * Math.PI]),
sy = d3.scaleSqrt().range([0, this.radius]);
for (var i = 0; i < items.length; i++) {
item = items[i];
text = this.GetValueLabelText(this.defSettings.valueLabel.type, item, "value");
if (item.coords.startAngle == 0.01)
progrGrad = (180 * item.coords.startAngle) / Math.PI;
if (progrGrad >= 360)
progrGrad = progrGrad - 360;
angleRad = item.coords.endAngle - item.coords.startAngle;
angleGrad = (180 * angleRad) / Math.PI;
radiusRot = -90 + (angleGrad / 2) + progrGrad;
if (progrGrad + (angleGrad / 2) >= 180)
radiusRot = radiusRot - 180;
// valutazione
radius = item.coords.outerRadius - item.coords.innerRadius,
maxH = 2 * radius * Math.sin(angleRad / 2);
var evalVL = evaluateFontVL(text, font, radius, maxH);
label = group.append("text")
.attr("x", function () {
sy(item.coords.innerRadius);
/*var factor = 1;
if (progrGrad + (angleGrad / 2) >= 180)
factor = -1;
return factor * (radius - offset);*/
})
/* .attr("y", 0)*/
.attr("transform", function () {
var angle = x(item.coords.startAngle + item.coords.endAngle / 2) - Math.PI / 2;
return "rotate(" + (angle / Math.PI * 180) + ")";
/* var y = item.coords.innerRadius;
if (progrGrad + (angleGrad / 2) >= 180)
y = - 1 * y;
return "rotate(" + radiusRot + ") translate(" + y + ")";*/
})
/* .style("text-anchor", function () {
if (progrGrad + (angleGrad / 2) >= 180)
return "start";
return "end";
})*/
.text(text);
setFont(label, evalVL.font, this);
progrGrad = progrGrad + angleGrad;
}
function evaluateFontVL(text, font, radius, maxH) {
var isOK = true,
mfont = JSON.stringify(font);
mfont = JSON.parse(mfont);
var txtW = getOffsetWidth(text, mfont, _this.chartId),
txtH = getOffsetHeight(text, mfont, _this.chartId),
fontRed = 0.25;
if (txtW > radius){
mfont.size = mfont.size - mfont.size * fontRed;
if (txtW > radius)
isOK = false;
}
if (txtH > maxH && isOK) {
mfont.size = mfont.size - mfont.size * fontRed;
txtH = getOffsetHeight(text, mfont, _this.chartId);
if (txtH > maxH)
isOK = false;
}
return { print : isOK, font : mfont };
}
}
ZtSunburstChart.prototype._SupportChangeOrder = function () {
return false;
}
ZtSunburstChart.prototype._SupportFilter = function () {
return false;
}
ZtSunburstChart.prototype._GetDefaultAnimateFunction = function (item, lastValueObj, duration, noOpacity) {
var div = this._GetAnimatedDivisor(),
elem = item.itm,
defaultValues = Empty(lastValueObj),
defaultObj = { x0: 0, x1: 0, y0: 0, y1: 0 };
if (!noOpacity) {
d3.select(elem)
.style("fill-opacity", 0)
.style("stroke-opacity", 0)
.transition()
.delay(item.depth * duration / div)
.duration(duration / div)
.attrTween("d", arcTween)
.style("fill-opacity", 1)
.style("stroke-opacity", 1)
}
/* else {
d3.select(elem)
.transition()
.delay(item.index * duration / div)
.duration(duration / div)
.attrTween("d", arcTween);
}
*/
function arcTween(a) {
var i = d3.interpolate(defaultValues ? defaultObj : this._lastValueObj, a),
arc = d3.arc()
.startAngle(function(d) { return d.x0; })
.endAngle(function(d) { return d.x1; })
.innerRadius(function(d) { return d.y0; })
.outerRadius(function(d) { return d.y1; });
return function(t) {
return arc(i(t));
};
}
}
ZtSunburstChart.prototype._GetAnimatedDivisor = function () {
if (!Empty(this.maxDepth) && this.maxDepth >= 0)
return this.maxDepth;
var max = 0;
this.items.map(function(d){ max = Math.max(d.depth, max); return d;})
this.maxDepth = max + 1;
return this.maxDepth;
}
ZtSunburstChart.prototype._GetItemObj = function (itemObject) {
var row = -1,
depth = itemObject.depth,
fidx = this.levelsIndex[this.levelsFields[depth]],
vidx = this.yIndex;
this._ZtChart.orgData.filter(function (rec, index) {
if (rec[fidx] == itemObject.category &&
rec[vidx] == itemObject.value ) {
row = index;
return true;
}
return false;
});
var ret = {
category: itemObject.category,
range: itemObject.range,
value: itemObject.value,
rowIdx: itemObject.hasChild ? -1 : row,
categoryCode: itemObject.categoryCode,
valueField: this.levelsFields[itemObject.depth],
isSelected : itemObject.isSelected,
focus : itemObject.focus,
multidimCurrentKey : this.appliedKey,
color: itemObject.color
};
return ret;
}
ZtSunburstChart.prototype._DrawValueLabels = function () {
var oldChartId = this.chartId,
_this = this,
font = appliedFont(this.defSettings, this.defSettings.valueLabel, this.defSettings.valueLabel.labelFont);
for (var i = 0; i < this._GetDivisor(); i++) {
this.chartId = oldChartId + i + "_";
var group = d3.select("#" + this.chartId + "d3Renderer").append("g")
.attr("id", this.chartId + "valueLabels")
.attr("transform", d3.select("#" + this.chartId + this.type + "_elementGroup").attr("transform")),
items = this.items.filter(function (item) { return item.valueField == _this.valueFields[i]; });
for (var j = 0; j < items.length; j++) {
var text = this.GetValueLabelText(this.defSettings.valueLabel.type, items[j], "value"),
oh = getOffsetHeight(text, font, this.chartId);
var label = group.append("text")
.attr("dy", oh + 5)
.append("textPath")
.attr("xlink:href", "#" + oldChartId + "pie_" + items[j].index + "_" + i + "_" + items[j].depth)
.attr("startOffset", "5px")
.text(text);
setFont(label, font, this);
}
}
this.chartId = oldChartId;
}
ZtSunburstChart.prototype._CreateGrid = function (thead, tbody1) {
// no prototipo treemap per mancanza di inclusione js
//table header
var td, innerdiv,
_this = this,
coords = this.levelsFields.concat(this.valueFields),
i;
if (!Empty(this.objConfig.labelsGrid)) {
var progrIndex = 0;
if (!Empty(this.objConfig.labelsGrid.key)) {
var labval = this.objConfig.labelsGrid.key.split(",");
for (i = 0; i < coords.length - 1; i++) {
if (!Empty(labval[i]))
coords[progrIndex] = labval[i];
progrIndex++;
}
}
if (!Empty(this.objConfig.labelsGrid.values))
coords[progrIndex] = this.objConfig.labelsGrid.values;
}
for (i = 0; i < coords.length; i++){
td = document.createElement("td");
td.className = "grid_title grid_cell_title grid_cell_title_table";
innerdiv = document.createElement("div");
// testo colonne campi
innerdiv.textContent = coords[i] //this._GetGridColumnName(this.propertyName[i]);
// this._SetGridColumnStyle(innerdiv, this.propertyName[i]);
td.appendChild(innerdiv);
thead.appendChild(td);
}
var pathValues = [],
chds,
root = (this.calcDataset.name == "ztc_root");
//table content
for (i = 0; i < this.calcDataset.children.length; i++) {
pathValues = [];
if (!root)
pathValues.push(this.calcDataset.name);
chds = this.calcDataset.children[i];
pathValues.push(chds.name);
fillRow(chds, pathValues, tbody1);
}
function fillRow(chds, path, tbody1) {
var i;
if (Empty(chds.children)) {
// terminale
path.push(chds.size);
var row = document.createElement("tr");
row.style.height = "42px";
row.className = "grid_row";
for (i = 0; i < path.length; i++) {
var cell = document.createElement("td"),
div3 = document.createElement("div");
div3.textContent = _this._GetGridCellValue(path[i], i, path);
cell.appendChild(div3);
row.appendChild(cell);
}
tbody1.appendChild(row);
path.pop();
return;
}
for (i = 0; i < chds.children.length; i++) {
var chd = chds.children[i];
path.push(chd.name);
fillRow(chd, path, tbody1);
path.pop();
}
}
}
ZtSunburstChart.prototype._GetGridCellValue = function (value, dataidx, record) {
var isLast = (dataidx == record.length - 1);
if (!isLast)
return value;
// apply picture + funzione
if (this.defSettings.valueLabel.applyPicture && this.defSettings.valuePicture.applyFunction) {
if (this.functionObj.GetValuePicture) {
var item = this._FindItemForGrid(record);
return this.functionObj.GetValuePicture(item);
}
}
else
return this.GetValuePicture(value);
}
ZtSunburstChart.prototype._FindItemForGrid = function (record) {
var itm = { path_depths: [] },
i;
for (i = 0; i < this.levelsFields.length; i++) {
itm.path_depths.push({
field: this.levelsFields[i],
value: record[i]
});
}
itm.value = record[record.length - 1];
itm.field = this.valueFields;
return itm;
}
ZtSunburstChart.prototype._GetParentPath = function (item) {
var parent_depth = [],
parent = item.parent;
parent_depth.push(item.name || item.category);
if (parent) {
var tpar = parent;
while (!Empty(parent.parent)) {
tpar = parent;
parent_depth.push(tpar.data.name);
parent = tpar.parent;
}
if (parent.data.name != "root")
parent_depth.push(parent.data.name);
}
return parent_depth.reverse();
}
ZtSunburstChart.prototype._GetItemForGrid = function (item) {
var rec_path = this._GetParentPath(item),
itm = { path_depths: [] },
i;
for (i = 0; i < this.levelsFields.length; i++) {
itm.path_depths.push({
field: this.levelsFields[i],
value: rec_path[i]
});
}
itm.value = item.value;
itm.field = this.valueFields;
return itm;
}