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

529 lines
17 KiB
JavaScript

function ZtForceChart(type) {
ZtTreeChart.apply(this, [type]);
this.viewBreadcrumb = false;
this.byCount = (this.type == "FORCESTR");
this.colorsTree = {};
}
ZtForceChart.prototype = Object.create(ZtTreeChart.prototype);
ZtForceChart.prototype.constructor = ZtForceChart;
ZtForceChart.prototype._SetChartSettingsJSON = function () {
ZtTreeChart.prototype._SetChartSettingsJSON.call(this);
this.defSettings.shape = this.chartConfig.graphSettings.shape;
//this.defSettings.shape.figureTypes = ["circle", "square", "triangle", "cross", "diamond", "star", "wye"];
this.defSettings.shape.figure = "circle"; // default
if (this.objConfig.mapSeries && !Empty(Object.keys(this.objConfig.mapSeries))) {
this.defSettings.shape.differSeries = true;
this.defSettings.shape.figureTypes = [];
this.defSettings.colorSeries = [];
var okys = Object.keys(this.objConfig.mapSeries);
for (var i = 0; i < okys.length; i++) {
this.defSettings.shape.figureTypes.push(this.objConfig.mapSeries[okys[i]].type);
this.defSettings.colorSeries.push({ color: this.objConfig.mapSeries[okys[i]].color, gradient: ""});
}
}
this.defSettings.animation.animate = true;
if (Empty(this.defSettings.animation.duration))
this.defSettings.animation.duration = 1000;
}
ZtForceChart.prototype._SetFieldsIndexes = function () {
ZtTreeChart.prototype._SetFieldsIndexes.call(this);
this.levelsClassIndex = {};
var lev = this.objConfig.labelSeries.split(",");
for (var i = 0; i < lev.length; i++) {
this.levelsClassIndex[lev[i]] = this.propertyName.indexOf(lev[i]);
}
}
ZtForceChart.prototype._SetLists = function () {
ZtTreeChart.prototype._SetLists.call(this);
if (!Empty(this.objConfig.labelSeries))
this.levelsLabelFields = this.objConfig.labelSeries.split(",");
if (!Empty(this.objConfig.fieldClass))
this.levelsClassFields = this.objConfig.fieldClass.split(",");
if (this.objConfig.mapSeries)
this.orgSeriesList = this.legendList = Object.keys(this.objConfig.mapSeries);
}
ZtForceChart.prototype._SetCalculationDataset = function () {
var addFields;
if (!this.byCount) {
var lSeries = !Empty(this.objConfig.labelSeries) ? this.objConfig.labelSeries : this.levelsFields[0];
addFields = [];
if (this.categoryCodeIndex >= 0)
addFields.push( { prop: "categoryCode", index: this.categoryCodeIndex } );
var hie = getHieDataset(this.dataSet, this.levelsFields, this.valueFields, lSeries, this.propertyName, addFields, true);
this.calcDataset = d3.hierarchy(hie);
this.categoryList = getListFromObjectArray(this.calcDataset.children, "data.name")
}
else {
addFields = [];
if (this.categoryCodeIndex >= 0)
addFields.push( { prop: "categoryCode", index: this.categoryCodeIndex } );
var robj = getForceDataset(this.dataSet, this.levelsFields, this.valueFields, this.propertyName, this.levelsClassFields, this.levelsLabelFields, addFields);
this.calcDataset = robj.nodes;
this.calcLinks = robj.links;
this.categoryList = robj.array.unique();
if (!Empty(this.levelsLabelFields)) {
this.orgCategoryList = robj.array;
this.categoryList = robj.labels.unique();
}
if (!this.objConfig.mapSeries || Empty(Object.keys(this.objConfig.mapSeries)))
this.orgSeriesList = this.legendList = this.categoryList.slice();
else
this.orgSeriesList = this.legendList = Object.keys(this.objConfig.mapSeries);
}
this.SetChartLegends();
}
ZtForceChart.prototype._DrawChartElements = function () {
var group = this.renderer.append("g")
.attr("id", this.chartId + this.type + "_elementGroup")
.attr("transform","translate(" + [0,0] + ")"),
radius = 5,
minlen = Math.min((this.chartWidth / 2 - this.marginOffsetX), (this.chartHeight / 2 - this.marginOffsetY)),
_this = this;
this.forceSimulationFnc = function () {
_this.svgDraw.link
.attr("x1", function (d) { return d.source.x; })
.attr("y1", function (d) { return d.source.y; })
.attr("x2", function (d) { return d.target.x; })
.attr("y2", function (d) { return d.target.y; });
_this.svgDraw.node.attr("transform", function(d) { return "translate(" + d.x + ", " + d.y + ")"; });
}
this.forceSimulation = d3.forceSimulation()
.force("center", d3.forceCenter(this.chartWidth / 2, this.chartHeight / 2))
.force("charge", d3.forceManyBody().strength(- Math.min(this.chartWidth / 2, this.chartHeight / 2) / 2))
.force("link", d3.forceLink().distance(minlen / 4))
.force("collide", d3.forceCollide()
.radius(function(d) {
if (_this.scaleZ && d.data.size)
return _this.scaleZ(d.data.size);
return radius;
})
)
.force("x", d3.forceX())
.force("y", d3.forceY())
.on("tick", this.forceSimulationFnc);
if (!this.drawStatic) {
/* parto dal presupposto che ?log(alphaMin) / log(1 - alphaDecay)?; by default, this is 300 (rif. API d3js)
e tengo fissata la parte log(alphaMin)
l'equazione da risolvere e' log(alphaMin) / log(1 - alphaDecay) = prevIterations
*/
var seconds = this.defSettings.animation.duration / 1000,
defaultIterations = 300,
defaultSeconds = 5,
prevIterations = (defaultIterations * seconds) / defaultSeconds,
alphaDecay = 1 - Math.exp(Math.log(this.forceSimulation.alphaMin()) / prevIterations);
if (alphaDecay < 0)
alphaDecay = 0;
if (alphaDecay > 1)
alphaDecay = 1;
this.forceSimulation.alphaDecay(alphaDecay);
}
this.DrawForceLayout(group, this.calcDataset);
}
ZtForceChart.prototype._SetElementsColor = function () {
this.SetColorSet();
var idx = 0,
gradID,
colD,
styleObj;
for (var i = 0; i < this.items.length; i++) {
idx = this.categoryList.indexOf(this.items[i].desc);
if (!this.byCount)
idx = i;
if (idx >= 0) {
this.items[i].idx = this.items[i].index;
if (!this.byCount) {
if (this.items[i].hasChild) {
if (!(this.items[i].category in this.colorsTree)) {
this.colorsTree[this.items[i].category] = this.colorSet[idx];
idx ++;
}
this.items[i].color = this.colorsTree[this.items[i].category];
}
else {
var parent = this.items[i].parent;
if (parent && parent.data) {
if (!(parent.data.name in this.colorsTree)) { // tutela
this.colorsTree[parent.data.name] = this.colorSet[idx];
idx ++;
}
this.items[i].color = this.colorsTree[parent.data.name];
}
}
}
else {
this.items[i].color = this.colorSet[idx];
if (this.objConfig.mapSeries) {
if (!Empty(this.items[i].class) && (this.items[i].class in this.objConfig.mapSeries)) {
if (this.objConfig.mapSeries[this.items[i].class].color)
this.items[i].color = { color: this.objConfig.mapSeries[this.items[i].class].color, 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;
styleObj.stroke = "#FAFAFA";
styleObj.stroke9width = "0.5px";
d3.select(this.items[i].itm).attr("style", makeStyleHTMLString(styleObj, d3.select(this.items[i].itm).attr("style")));
}
}
styleObj.fill = "none";
styleObj.stroke = this.defSettings.line.color || "#D0D0D0";
styleObj.stroke9width = (this.defSettings.line.stroke || 0.5) + "px";
if (this.items.length > 1) {
this.svg
.selectAll(".link")
.attr("style", makeStyleHTMLString(styleObj, this.svg.selectAll(".link").attr("style")));
}
}
ZtForceChart.prototype._ApplyMouseOver = function (item, itemObj) {
StdChart.prototype._ApplyMouseOver.call(this, item, itemObj);
}
ZtForceChart.prototype.AppendHoverItem = function (item, itemObj) {
StdChart.prototype.AppendHoverItem.call(this, item, itemObj);
}
ZtForceChart.prototype._SelectItem = function (itemObject, select) {
StdChart.prototype._SelectItem.call(this, itemObject, select);
if (this.byCount)
return;
if (!itemObject.hasChild || !this.scaleZ)
return;
var fobj = this._FindNode(this.calcDataset.children, itemObject.category, []),
current;
if (fobj.found && fobj.progr.length >= 1) {
current = this.calcDataset.children[fobj.progr[0]];
for (var i = 1; i < fobj.progr.length; i++) {
current = current.children[fobj.progr[i]];
}
if (current.children && current.children.length >= 1) {
current.data._size = current.data.size;
current.data.size = d3.max(this.allValuesZ) * 2;
current._children = current.children;
current.children = null;
}
else {
current.data.size = current.data._size;
current.data._size = null;
current.children = current._children;
current._children = null;
}
}
this._UpdateElements();
}
ZtForceChart.prototype._UpdateElements = function () {
var group = this.svg.select("#" + this.chartId + this.type + "_elementGroup");
group.selectAll("g").remove();
this.RemoveAllHovers();
this.ResetItems();
this.DrawForceLayout(group, this.calcDataset);
this.AfterDraw();
this.forceSimulation.restart();
this.forceSimulation.alphaTarget(0);
}
ZtForceChart.prototype._GetItem = function (prop, value) {
return this._GetItems().filter(function (it) { return it[prop] == value; })[0];
}
ZtForceChart.prototype._FindNode = function (chd, key, progr) {
var found = false,
obj = {};
for (var i = 0; !found && i < chd.length; i++) {
if (chd[i].data && chd[i].data.name == key) {
found = true;
progr.push(i);
}
else if (chd[i].children) {
obj = this._FindNode(chd[i].children, key, progr);
found = obj.found;
progr = obj.progr;
if (found)
progr.splice(progr.length - 1, 0, i);
}
}
return { found : found, progr : progr};
}
ZtForceChart.prototype._GetNodeSize = function (node, size) {
for (var i = 0; i < node.children.length; i++) {
if (node.children[i].data && ("size" in node.children[i].data))
size += node.children[i].data.size;
else
size = this._GetNodeSize(node.children[i], size);
}
return size;
}
ZtForceChart.prototype._GetDefaultAnimateFunction = function (/*item, lastValueObj, duration*/) { }
ZtForceChart.prototype._GetParametersStringForTooltip = function (item, itemObject) {
var purl = "";
if (this.byCount) {
// dep
if (!Empty(itemObject.key))
purl += "&key=" + URLenc(itemObject.key);
if (!Empty(itemObject.desc))
purl += "&category=" + URLenc(itemObject.desc);
if (!Empty(itemObject.class))
purl += "&serie=" + URLenc(itemObject.class);
}
else {
if (!Empty(itemObject.category))
purl += "&category=" + URLenc(itemObject.category);
}
if (!Empty(itemObject.value)) {
var val = itemObject.value;
// apply picture + funzione
if (this.defSettings.valueLabel.applyPicture && this.defSettings.valuePicture.applyFunction) {
if (this.functionObj.GetValuePicture) {
val = this.functionObj.GetValuePicture(this._GetItemForGrid(itemObject));
}
}
purl += "&value=" + URLenc(val);
}
return purl;
}
ZtForceChart.prototype._GetParametersStringForLink = function (item) {
var purl = "";
if (this.byCount) {
// dep
if (!Empty(item.keyF))
purl += "&key=" + URLenc(item.keyF);
if (!Empty(item.category))
purl += "&category=" + URLenc(item.category);
if (!Empty(item.series))
purl += "&serie=" + URLenc(item.series);
}
else {
if (!Empty(item.category))
purl += "&category=" + URLenc(item.category);
}
if (!Empty(item.value)) {
var val = item.value;
// apply picture + funzione
if (this.defSettings.valueLabel.applyPicture && this.defSettings.valuePicture.applyFunction) {
if (this.functionObj.GetValuePicture) {
val = this.functionObj.GetValuePicture(this._GetItemForGrid(item));
}
}
purl += "&value=" + URLenc(val);
}
return purl;
}
ZtForceChart.prototype._GetItemObj = function (itemObject) {
var ret;
if (this.byCount) {
// dep
ret = {
category: itemObject.desc,
series: itemObject.class,
value: itemObject.value,
categoryCode: itemObject.categoryCode,
keyF: itemObject.key,
rowIdx: -1,
isSelected : itemObject.isSelected,
multidimCurrentKey : this.appliedKey,
color: itemObject.color
}
}
else {
// hie
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;
});
ret = {
category: itemObject.category,
parent: itemObject.parentName,
value: itemObject.value,
rowIdx: itemObject.hasChild ? -1 : row,
categoryCode: itemObject.categoryCode,
depth: itemObject.depth,
isSelected : itemObject.isSelected,
multidimCurrentKey : this.appliedKey
}
}
return ret;
}
ZtForceChart.prototype._HasShapes = function () {
return true;
}
ZtForceChart.prototype._EvaluateAutomaticScales = function () {
if (this.objConfig.mapSeries && !Empty(Object.keys(this.objConfig.mapSeries)))
this.objConfig.manualScale = true;
}
ZtForceChart.prototype._GetReferredList = function () {
return this.legendList;
}
ZtForceChart.prototype._GetDrawingList = function () {
return this.legendList;
}
ZtForceChart.prototype._CreateGrid = function (thead, tbody1) {
//table header
var td, innerdiv,
i,
fields = this.levelsFields.slice(),
coords;
if (!Empty(this.valueFields))
fields.push(this.valueFields);
coords = fields.slice();
if (!Empty(this.objConfig.labelsGrid)) {
var progrIndex = 0;
if (!Empty(this.objConfig.labelsGrid.key)) {
var labval = this.objConfig.labelsGrid.key.split(","),
end = !Empty(this.valueFields) ? coords.length - 1 : coords.length;
for (i = 0; i < end; i++) {
if (!Empty(labval[i]))
coords[progrIndex] = labval[i];
progrIndex++;
}
}
if (!Empty(this.valueFields) && !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];
td.appendChild(innerdiv);
thead.appendChild(td);
}
//table content
this.__gfields = fields.slice();
for (i = 0; i < this.dataSet.length; i++) {
var vals = this.dataSet[i],
row = document.createElement("tr");
row.style.height = "42px";
if (i == 0 || i % 2 == 0) {
row.className = "grid_rowodd";
}
else {
row.className = "grid_row";
}
for (var b = 0; b < fields.length; b++) {
var cell = document.createElement("td"),
div3 = document.createElement("div"),
idx = this.propertyName.indexOf(fields[b]);
div3.textContent = this._GetGridCellValue(vals[idx], b, vals);
cell.appendChild(div3);
row.appendChild(cell);
}
tbody1.appendChild(row);
}
}
ZtForceChart.prototype._GetGridCellValue = function (value, dataidx, record) {
return ZtSunburstChart.prototype._GetGridCellValue.call(this, value, dataidx, record);
}
ZtForceChart.prototype._FindItemForGrid = function (record) {
if (this.byCount) {
var itm = {},
idx;
idx = this.propertyName.indexOf(this.valueFields);
itm.value = record[idx];
idx = this.propertyName.indexOf(this.levelsFields[1]);
itm.desc = record[idx];
itm.index = this.orgSeriesList.indexOf(itm.desc);
return this._GetItemForGrid(itm);
}
else
return ZtSunburstChart.prototype._FindItemForGrid.call(this, record);
}
ZtForceChart.prototype._GetParentPath = function (item) {
return ZtSunburstChart.prototype._GetParentPath.call(this, item);
}
ZtForceChart.prototype._GetItemForGrid = function (item) {
if (this.byCount) {
var itm = {},
i;
itm.node = item.desc;
itm.value = item.value;
itm.field = this.valueFields;
itm.source = {};
itm.source.field = this.levelsFields[0];
itm.source.values = [];
itm.target = {};
itm.target.field = this.levelsFields[1];
itm.target.values = [];
for (i = 0; i < this.calcLinks.length; i++) {
var link = this.calcLinks[i];
// item come target
if (link.target.index == item.index) {
if (itm.source.values.indexOf(link.source.name) < 0)
itm.source.values.push(link.source.name);
}
// item come source
if (link.source.index == item.index) {
if (itm.target.values.indexOf(link.target.name) < 0)
itm.target.values.push(link.target.name);
}
}
// class
// labels
return itm;
}
else
return ZtSunburstChart.prototype._GetItemForGrid.call(this, item);
}