Browse Source

Sankey Charts mit D3 V7.8 #6

viz_worldmap
Daniel Quathamer 2 years ago
parent
commit
520e622902
  1. 4
      src-modules/module/viz/conf/includes.txt
  2. 2
      src-modules/module/viz/conf/viz.xml
  3. 33
      src-modules/module/viz/schluesseltabellen/viz_property.unl
  4. 21
      src-modules/module/viz/schluesseltabellen/viz_property_group.unl
  5. 2
      src-modules/module/viz/schluesseltabellen/viz_property_renderer.unl
  6. 1
      src-modules/module/viz/schluesseltabellen/viz_renderer.unl
  7. 2
      src-modules/module/viz/schluesseltabellen/viz_type.unl
  8. 11
      src-modules/module/viz/schluesseltabellen/viz_type_property.unl
  9. 425
      superx/xml/js/viz/d3-sankey.js
  10. 5
      superx/xml/js/viz/d3.v3.min.js
  11. 518
      superx/xml/js/viz/sankey_v3.js
  12. 253
      superx/xml/js/viz/viz_functions.js
  13. 6
      superx/xml/viz_html_chart.xsl

4
src-modules/module/viz/conf/includes.txt

@ -8,11 +8,11 @@ style/sx_viz_muster.css
style/bulma-tooltip.min.css style/bulma-tooltip.min.css
style/LICENSE_bulma_tooltip_1.2.0.txt style/LICENSE_bulma_tooltip_1.2.0.txt
WEB-INF/conf/edustore/db/bin/SQL_ENV_viz.sam WEB-INF/conf/edustore/db/bin/SQL_ENV_viz.sam
xml/js/viz/d3.v3.min.js xml/js/viz/d3.min.js
xml/js/viz/d3-7.8.0-license.txt xml/js/viz/d3-7.8.0-license.txt
xml/js/viz/plot.js xml/js/viz/plot.js
xml/js/viz/plot-0.6.1-license.txt xml/js/viz/plot-0.6.1-license.txt
xml/js/viz/sankey.js xml/js/viz/d3-sankey.js
xml/js/viz/viz_functions.js xml/js/viz/viz_functions.js
xml/viz_html_chart.xsl xml/viz_html_chart.xsl
xml/viz_html_chart_sankey.xsl xml/viz_html_chart_sankey.xsl

2
src-modules/module/viz/conf/viz.xml

@ -315,7 +315,7 @@ and G.uniquename in ('CATEGORY','MEASURE')
</functions> </functions>
<themen> <themen>
<thema name="Administration Visualisierungen" <thema name="Administration Visualisierungen"
parent="Masken verwalten">Abfragen zur Administration von Visualisierungen </thema> parent="Visualisierungen">Abfragen zur Administration von Visualisierungen </thema>
</themen> </themen>
<masken> <masken>

33
src-modules/module/viz/schluesseltabellen/viz_property.unl

@ -1,11 +1,11 @@
1^Grafik-Höhe^height^^px^1^ ^0^4^10^Diagrammhöhe (exkl. Skalenbeschriftung). Wird nur ausgewertet wenn es keine Y-Achse gibt!^101^^^integer^ 1^Grafik-Höhe^height^450^px^1^ ^0^4^10^Diagrammhöhe (exkl. Skalenbeschriftung). Wird nur ausgewertet wenn es keine Y-Achse gibt!^101^^^integer^
2^Grafik-Breite^width^^px^1^ ^0^4^10^Diagrammsbreite (exkl.Skalenbeschriftung)^102^100^2000^integer^ 2^Grafik-Breite^width^650^px^1^ ^0^4^10^Diagrammsbreite (exkl.Skalenbeschriftung)^102^100^2000^integer^
3^Werte-Label-Breite^valueLabelWidth^^px^1^^0^1^18^^^^^integer^ 3^Werte-Label-Breite^valueLabelWidth^^px^1^^0^1^18^^^^^integer^
4^Hintergrundfarbe^backgroundColor^#ffffff^ ^1^#ffffeb^0^3^11^Hintergrundfarbe der Grafik^201^^^string^ 4^Hintergrundfarbe^backgroundColor^#ffffff^ ^1^#ffffeb^0^3^20^Hintergrundfarbe der Grafik^201^^^string^
5^Vordergrundfarbe^color^^ ^1^black^0^3^11^Farbe von Text- und Diagrammelementen^202^^^string^ 5^Vordergrundfarbe^color^^ ^1^black^0^3^20^Farbe von Text- und Diagrammelementen^202^^^string^
6^Schriftgröße^fontSize^^px^1^ ^0^4^11^Schriftgröße der Skalenbeschriftung^204^^^integer^ 6^Schriftgröße^fontSize^^px^1^ ^0^4^11^Schriftgröße der Skalenbeschriftung^204^^^integer^
7^Schriftfamilie^fontFamily^^ ^1^serif|sans-serif|monospace|system_ui^0^2^11^Schriftfamlilie der Skalenbeschriftung^203^^^string^ 7^Schriftfamilie^fontFamily^^ ^1^serif|sans-serif|monospace|system_ui^0^2^11^Schriftfamlilie der Skalenbeschriftung^203^^^string^
8^Flächenfarbe^fill_static^^ ^1^ ^0^3^11^Füllfarbe (nur) von Diagrammelementen (Flächen, Balken, Säulen, Streifen, Punkte)^305^^^string^ 8^Flächenfarbe^fill_static^ ^ ^1^ ^0^3^20^Nur für Grafikelement Flächen. Füllfarbe.^305^^^string^
11^X: Schriftneigung^tickRotate_x^^ ^1^ ^0^1^18^Neigungswinkel der Achsenwerte^604^^^integer^ 11^X: Schriftneigung^tickRotate_x^^ ^1^ ^0^1^18^Neigungswinkel der Achsenwerte^604^^^integer^
12^X: Skalierung^ticks_x^^ ^1^ ^0^1^18^Feinheit der Wertegliederung^605^^^integer^ 12^X: Skalierung^ticks_x^^ ^1^ ^0^1^18^Feinheit der Wertegliederung^605^^^integer^
13^X: Schriftgröße^tickSize_x^^ ^1^ ^0^1^18^Größe der Achsenwerte^603^^^integer^ 13^X: Schriftgröße^tickSize_x^^ ^1^ ^0^1^18^Größe der Achsenwerte^603^^^integer^
@ -18,26 +18,25 @@
21^Innenrand unten^insetBottom^ ^px^1^ ^0^4^10^Abstand zwischen Grafik und Achsenbeschriftung unten^108^^^integer^ 21^Innenrand unten^insetBottom^ ^px^1^ ^0^4^10^Abstand zwischen Grafik und Achsenbeschriftung unten^108^^^integer^
22^Innenrand links^insetLeft^ ^px^1^ ^0^4^10^Abstand zwischen Grafik und Achsenbeschriftung links^109^^^integer^ 22^Innenrand links^insetLeft^ ^px^1^ ^0^4^10^Abstand zwischen Grafik und Achsenbeschriftung links^109^^^integer^
23^Innenrand rechts^insetRight^ ^px^1^ ^0^4^10^Abstand zwischen Grafik und Achsenbeschriftung rechts^110^^^integer^ 23^Innenrand rechts^insetRight^ ^px^1^ ^0^4^10^Abstand zwischen Grafik und Achsenbeschriftung rechts^110^^^integer^
24^Farbschema^scheme^^ ^1^blues|greens|greys|oranges|purples|reds^0^2^20^Farbschema von Diagrammelemente^303^^^string^ 24^Farbschema^scheme^ ^ ^1^blues|greens|greys|oranges|purples|reds^0^2^20^Nur für Grafikelemente Balken und Linien: Farbtonschema für Serien.^303^^^string^
25^Farbtyp^type^^ ^1^einfarbig|mehrfarbig|zyklisch^0^2^12^Ein-/Mehrfarbigkeit von Diagrammelementen^302^^^string^ 25^Farbtyp^type^^ ^1^einfarbig|mehrfarbig|zyklisch^0^2^20^Ein-/Mehrfarbigkeit von Diagrammelementen^302^^^string^
43^Farbsättigung^fillOpacity^^ ^1^ ^0^4^12^Deckkraft der Füllfarbe von Diagrammelementen^306^^^string^ 43^Farbsättigung^fillOpacity^^ ^1^ ^0^4^20^Deckkraft der Füllfarbe von Diagrammelementen^306^^^string^
45^Strichdicke^strokeWidth^^ ^1^ ^0^1^12^Strichdicke von Diagrammelementen (relevant für Plot.dot, Plot.tickX/Y)^308^^^string^ 45^Strichdicke^strokeWidth^^ ^1^ ^0^1^12^Strichdicke von Diagrammelementen (relevant für Plot.dot, Plot.tickX/Y)^308^^^string^
56^Fortlaufende Skala^continous scales^^ ^1^identity|linear|log|pow|sqrt|symlog^0^2^15^Art der Skalen-Gliederung^401^^^string^ 56^Fortlaufende Skala^continous scales^^ ^1^identity|linear|log|pow|sqrt|symlog^0^2^15^Art der Skalen-Gliederung^401^^^string^
57^Kategorie-Skala^categorical scales^^ ^1^point|band^0^2^15^Art der Skalen-Gliederung^402^^^string^ 57^Kategorie-Skala^categorical scales^^ ^1^point|band^0^2^15^Art der Skalen-Gliederung^402^^^string^
58^Datums-Skala^date scales^^ ^1^time|utc^0^2^15^Art der Skalen-Gliederung^403^^^string^ 58^Datums-Skala^date scales^^ ^1^time|utc^0^2^15^Art der Skalen-Gliederung^403^^^string^
60^Farbschema-Typ^schemetype^^ ^1^linear|sqrt|pow|log|symlog|sequential|cyclical|quantile^0^2^12^Art der Farbverteilung in Diagrammelementen^304^^^string^ 60^Farbschema-Typ^schemetype^^ ^1^linear|sqrt|pow|log|symlog|sequential|cyclical|quantile^0^2^20^Art der Farbverteilung in Diagrammelementen^304^^^string^
61^Elementtyp^marks^ ^ ^1^Plot.line|Plot.dot|Plot.areaX|Plot.areaY.|Plot.barX|Plot.barY|Plot.rectX|Plot.rectY|Plot.ruleX|Plot.ruleY|Plot.tickX|Plot.tickY|Plot.arrow|Plot.cell|Plot.text|Plot.link|Plot.image^0^2^12^Ausrichtung und Form der grafischen Elemente^301^^^string^ 61^Grafik-Elementtyp^marks^ ^ ^1^Plot.line|Plot.dot|Plot.areaX|Plot.areaY.|Plot.barX|Plot.barY|Plot.rectX|Plot.rectY|Plot.ruleX|Plot.ruleY|Plot.tickX|Plot.tickY|Plot.arrow|Plot.cell|Plot.text|Plot.link|Plot.image^0^2^12^Ausrichtung und Form der grafischen Elemente^301^^^string^
63^X: Label-Abstand^labelOffset_x^^px^1^ ^0^1^18^Label-Abstand von Achse^602^^^integer^ 63^X: Label-Abstand^labelOffset_x^^px^1^ ^0^1^18^Label-Abstand von Achse^602^^^integer^
68^Maß: Chart-Abstand^gridChartOffset^^ ^1^ ^0^1^18^ ^607^^^string^ 68^Maß: Chart-Abstand^gridChartOffset^^ ^1^ ^0^1^18^ ^607^^^string^
69^Maß: Label-Höhe^gridLabelHeight^^px^1^ ^0^1^18^ ^608^^^integer^ 69^Maß: Label-Höhe^gridLabelHeight^^px^1^ ^0^1^18^ ^608^^^integer^
70^X-Achse^x^^ ^1^ ^0^1^5^ ^608^^^string^ 70^X-Achse^x^^ ^1^ ^0^1^5^ ^608^^^string^
71^Kategorie-Dimension 1^viz_dimension1^^ ^1^ ^0^1^5^ ^608^^^string^
72^Y-Achse^y^^ ^1^ ^0^1^6^ ^608^^^string^ 72^Y-Achse^y^^ ^1^ ^0^1^6^ ^608^^^string^
73^Maß 1^viz_measure1^^ ^1^ ^0^1^6^ ^608^^^string^ 73^Maß 1^measure1^^ ^1^ ^0^1^6^ ^608^^^string^
76^Serien-Dimension^stroke^^ ^1^ ^0^1^5^ ^608^^^string^ 76^Serien-Dimension^stroke^^ ^1^ ^0^1^5^ ^608^^^string^
78^Legende^legend^^ ^1^true|false^0^2^20^ ^303^^^boolean^ 78^Legende^legend^^ ^1^true|false^0^2^11^ ^303^^^boolean^
79^Beschriftung^text^ ^ ^1^ ^0^1^5^ ^608^^^string^ 79^Beschriftung^text^ ^ ^1^ ^0^1^5^ ^608^^^string^
80^Serienfarbe^fill^^ ^1^ ^0^1^5^Füllfarbe (nur) von Diagrammelementen (Flächen, Balken, Säulen, Streifen, Punkte)^305^^^string^ 80^Serienfarbe^fill^ ^ ^1^ ^0^1^20^Nur für Grafikelemente Balken und Linien: Merkmal der Serien-Dimension^305^^^string^
81^Y: Label-Abstand^labelOffset_y^^px^1^ ^0^1^21^Label-Abstand von Achse^602^^^integer^ 81^Y: Label-Abstand^labelOffset_y^^px^1^ ^0^1^21^Label-Abstand von Achse^602^^^integer^
82^Y: Label-Ausrichtung^labelAnchor_y^^ ^1^left|center|right^0^2^21^Label-Position^601^^^string^ 82^Y: Label-Ausrichtung^labelAnchor_y^^ ^1^left|center|right^0^2^21^Label-Position^601^^^string^
83^Y: Schriftgröße^tickSize_y^^ ^1^ ^0^1^21^Größe der Achsenwerte^603^^^integer^ 83^Y: Schriftgröße^tickSize_y^^ ^1^ ^0^1^21^Größe der Achsenwerte^603^^^integer^
@ -46,7 +45,9 @@
86^X: Label^label_x^^ ^1^ ^0^1^18^Label X-Achse^602^^^string^ 86^X: Label^label_x^^ ^1^ ^0^1^18^Label X-Achse^602^^^string^
87^Y: Label^label_y^^ ^1^ ^0^1^21^Label Y-Achse^602^^^string^ 87^Y: Label^label_y^^ ^1^ ^0^1^21^Label Y-Achse^602^^^string^
88^Punktdicke^r^^ ^1^ ^0^1^5^Punktdicke von Diagrammelementen (relevant für Plot.dot, Plot.tickX/Y)^308^^^string^ 88^Punktdicke^r^^ ^1^ ^0^1^5^Punktdicke von Diagrammelementen (relevant für Plot.dot, Plot.tickX/Y)^308^^^string^
89^Sortierung^sort^^ ^1^ ^0^1^5^ ^608^^^string^
90^Kategorie-Dimension 2^viz_dimension2^^ ^1^ ^0^1^5^ ^608^^^string^
91^Quell-Dimension^viz_source^^ ^1^ ^0^1^5^ ^608^^^string^ 91^Quell-Dimension^viz_source^^ ^1^ ^0^1^5^ ^608^^^string^
92^Ziel-Dimension 1^viz_target1^^ ^1^ ^0^1^5^ ^608^^^string^ 92^Ziel-Dimension 1^viz_target1^^ ^1^ ^0^1^5^ ^608^^^string^
93^X: Linie^line_x^true^ ^1^true|false^0^2^18^Linie X-Achse^602^^^boolean^
94^Y: Linie^line_y^true^ ^1^true|false^0^2^21^Linie Y-Achse^602^^^boolean^
95^Dimension 1^dimension1^^ ^1^ ^0^1^5^ ^608^^^string^
96^Dimension 2^dimension2^^ ^1^ ^0^1^5^ ^608^^^string^

21
src-modules/module/viz/schluesseltabellen/viz_property_group.unl

@ -1,11 +1,10 @@
5^CATEGORY^Kategorie-Achse^60^ 5^CATEGORY^Kategorie-Achse^70^
6^MEASURE^Maß-Achse^70^ 6^MEASURE^Maß-Achse^80^
10^LAYOUT^Größe und Ränder^10^ 10^LAYOUT^Größe und Ränder^20^
11^STYLE^Formatierung^20^ 11^STYLE^Formatierung^30^
12^MARKS^Grafik-Elemente^30^ 12^MARKS^Grafik-Elemente^10^
15^SCALES^Skalen-Typen^40^ 15^SCALES^Skalen-Typen^100^
17^AXIS^Achsen-Customizing^50^ 18^TICKS_LABELS_X^X-Achsen-Beschriftung^60^
18^TICKS_LABELS_X^X Achsen-Beschriftung^^ 19^TICKFORMATTING^Zahlen-, Datumsformat^90^
19^TICKFORMATTING^Zahlen-, Datumsformat^80^ 20^COLOR^Farben^40^
20^COLOR^Farben^90^ 21^TICKS_LABELS_Y^Y-Achsen-Beschriftung^50^
21^TICKS_LABELS_Y^Y Achsen-Beschriftung^^

2
src-modules/module/viz/schluesseltabellen/viz_property_renderer.unl

@ -23,3 +23,5 @@
25^2^87^label^ 25^2^87^label^
26^2^84^tickRotate^ 26^2^84^tickRotate^
27^2^79^text^ 27^2^79^text^
28^2^93^line^
29^2^94^line^

1
src-modules/module/viz/schluesseltabellen/viz_renderer.unl

@ -1,3 +1,2 @@
1^d3js^D3JS (V7)^ 1^d3js^D3JS (V7)^
2^plot^Observable Plot^ 2^plot^Observable Plot^
3^d3jsv3^D3JS (V3)^

2
src-modules/module/viz/schluesseltabellen/viz_type.unl

@ -8,4 +8,4 @@
9^box_y^Boxplot (vertikal)^2^ ^ ^V^ 9^box_y^Boxplot (vertikal)^2^ ^ ^V^
10^text^Wertelabel^2^ ^ ^^ 10^text^Wertelabel^2^ ^ ^^
11^bar_x_d3^Balken (horizontal)^1^^^H^ 11^bar_x_d3^Balken (horizontal)^1^^^H^
12^sankey^Sankey^3^/superx/xml/js/viz/sankey.js^^C^ 12^sankey^Sankey^1^/superx/xml/js/viz/sankey.js^^H^

11
src-modules/module/viz/schluesseltabellen/viz_type_property.unl

@ -19,15 +19,14 @@
34^7^72^0^0^ 34^7^72^0^0^
35^9^70^0^0^ 35^9^70^0^0^
36^9^72^1^0^ 36^9^72^1^0^
37^8^8^0^0^ 37^8^80^0^0^
38^8^72^1^0^ 38^8^72^1^0^
39^8^70^1^0^ 39^8^70^1^0^
40^8^89^0^0^
41^10^70^0^0^ 41^10^70^0^0^
42^10^72^0^10^ 42^10^72^0^10^
43^10^79^1^20^ 43^10^79^1^20^
44^11^71^1^0^ 44^11^95^1^0^
45^11^73^1^0^ 45^11^73^1^0^
46^12^73^1^0^ 46^12^73^1^20^
47^12^71^1^0^ 47^12^95^1^1^
48^12^90^1^0^ 48^12^96^1^10^

425
superx/xml/js/viz/d3-sankey.js vendored

@ -0,0 +1,425 @@
// https://github.com/d3/d3-sankey v0.12.3 Copyright 2019 Mike Bostock
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array'), require('d3-shape')) :
typeof define === 'function' && define.amd ? define(['exports', 'd3-array', 'd3-shape'], factory) :
(global = global || self, factory(global.d3 = global.d3 || {}, global.d3, global.d3));
}(this, function (exports, d3Array, d3Shape) { 'use strict';
function targetDepth(d) {
return d.target.depth;
}
function left(node) {
return node.depth;
}
function right(node, n) {
return n - 1 - node.height;
}
function justify(node, n) {
return node.sourceLinks.length ? node.depth : n - 1;
}
function center(node) {
return node.targetLinks.length ? node.depth
: node.sourceLinks.length ? d3Array.min(node.sourceLinks, targetDepth) - 1
: 0;
}
function constant(x) {
return function() {
return x;
};
}
function ascendingSourceBreadth(a, b) {
return ascendingBreadth(a.source, b.source) || a.index - b.index;
}
function ascendingTargetBreadth(a, b) {
return ascendingBreadth(a.target, b.target) || a.index - b.index;
}
function ascendingBreadth(a, b) {
return a.y0 - b.y0;
}
function value(d) {
return d.value;
}
function defaultId(d) {
return d.index;
}
function defaultNodes(graph) {
return graph.nodes;
}
function defaultLinks(graph) {
return graph.links;
}
function find(nodeById, id) {
const node = nodeById.get(id);
if (!node) throw new Error("missing: " + id);
return node;
}
function computeLinkBreadths({nodes}) {
for (const node of nodes) {
let y0 = node.y0;
let y1 = y0;
for (const link of node.sourceLinks) {
link.y0 = y0 + link.width / 2;
y0 += link.width;
}
for (const link of node.targetLinks) {
link.y1 = y1 + link.width / 2;
y1 += link.width;
}
}
}
function Sankey() {
let x0 = 0, y0 = 0, x1 = 1, y1 = 1; // extent
let dx = 24; // nodeWidth
let dy = 8, py; // nodePadding
let id = defaultId;
let align = justify;
let sort;
let linkSort;
let nodes = defaultNodes;
let links = defaultLinks;
let iterations = 6;
function sankey() {
const graph = {nodes: nodes.apply(null, arguments), links: links.apply(null, arguments)};
computeNodeLinks(graph);
computeNodeValues(graph);
computeNodeDepths(graph);
computeNodeHeights(graph);
computeNodeBreadths(graph);
computeLinkBreadths(graph);
return graph;
}
sankey.update = function(graph) {
computeLinkBreadths(graph);
return graph;
};
sankey.nodeId = function(_) {
return arguments.length ? (id = typeof _ === "function" ? _ : constant(_), sankey) : id;
};
sankey.nodeAlign = function(_) {
return arguments.length ? (align = typeof _ === "function" ? _ : constant(_), sankey) : align;
};
sankey.nodeSort = function(_) {
return arguments.length ? (sort = _, sankey) : sort;
};
sankey.nodeWidth = function(_) {
return arguments.length ? (dx = +_, sankey) : dx;
};
sankey.nodePadding = function(_) {
return arguments.length ? (dy = py = +_, sankey) : dy;
};
sankey.nodes = function(_) {
return arguments.length ? (nodes = typeof _ === "function" ? _ : constant(_), sankey) : nodes;
};
sankey.links = function(_) {
return arguments.length ? (links = typeof _ === "function" ? _ : constant(_), sankey) : links;
};
sankey.linkSort = function(_) {
return arguments.length ? (linkSort = _, sankey) : linkSort;
};
sankey.size = function(_) {
return arguments.length ? (x0 = y0 = 0, x1 = +_[0], y1 = +_[1], sankey) : [x1 - x0, y1 - y0];
};
sankey.extent = function(_) {
return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], sankey) : [[x0, y0], [x1, y1]];
};
sankey.iterations = function(_) {
return arguments.length ? (iterations = +_, sankey) : iterations;
};
function computeNodeLinks({nodes, links}) {
for (const [i, node] of nodes.entries()) {
node.index = i;
node.sourceLinks = [];
node.targetLinks = [];
}
const nodeById = new Map(nodes.map((d, i) => [id(d, i, nodes), d]));
for (const [i, link] of links.entries()) {
link.index = i;
let {source, target} = link;
if (typeof source !== "object") source = link.source = find(nodeById, source);
if (typeof target !== "object") target = link.target = find(nodeById, target);
source.sourceLinks.push(link);
target.targetLinks.push(link);
}
if (linkSort != null) {
for (const {sourceLinks, targetLinks} of nodes) {
sourceLinks.sort(linkSort);
targetLinks.sort(linkSort);
}
}
}
function computeNodeValues({nodes}) {
for (const node of nodes) {
node.value = node.fixedValue === undefined
? Math.max(d3Array.sum(node.sourceLinks, value), d3Array.sum(node.targetLinks, value))
: node.fixedValue;
}
}
function computeNodeDepths({nodes}) {
const n = nodes.length;
let current = new Set(nodes);
let next = new Set;
let x = 0;
while (current.size) {
for (const node of current) {
node.depth = x;
for (const {target} of node.sourceLinks) {
next.add(target);
}
}
if (++x > n) throw new Error("circular link");
current = next;
next = new Set;
}
}
function computeNodeHeights({nodes}) {
const n = nodes.length;
let current = new Set(nodes);
let next = new Set;
let x = 0;
while (current.size) {
for (const node of current) {
node.height = x;
for (const {source} of node.targetLinks) {
next.add(source);
}
}
if (++x > n) throw new Error("circular link");
current = next;
next = new Set;
}
}
function computeNodeLayers({nodes}) {
const x = d3Array.max(nodes, d => d.depth) + 1;
const kx = (x1 - x0 - dx) / (x - 1);
const columns = new Array(x);
for (const node of nodes) {
const i = Math.max(0, Math.min(x - 1, Math.floor(align.call(null, node, x))));
node.layer = i;
node.x0 = x0 + i * kx;
node.x1 = node.x0 + dx;
if (columns[i]) columns[i].push(node);
else columns[i] = [node];
}
if (sort) for (const column of columns) {
column.sort(sort);
}
return columns;
}
function initializeNodeBreadths(columns) {
const ky = d3Array.min(columns, c => (y1 - y0 - (c.length - 1) * py) / d3Array.sum(c, value));
for (const nodes of columns) {
let y = y0;
for (const node of nodes) {
node.y0 = y;
node.y1 = y + node.value * ky;
y = node.y1 + py;
for (const link of node.sourceLinks) {
link.width = link.value * ky;
}
}
y = (y1 - y + py) / (nodes.length + 1);
for (let i = 0; i < nodes.length; ++i) {
const node = nodes[i];
node.y0 += y * (i + 1);
node.y1 += y * (i + 1);
}
reorderLinks(nodes);
}
}
function computeNodeBreadths(graph) {
const columns = computeNodeLayers(graph);
py = Math.min(dy, (y1 - y0) / (d3Array.max(columns, c => c.length) - 1));
initializeNodeBreadths(columns);
for (let i = 0; i < iterations; ++i) {
const alpha = Math.pow(0.99, i);
const beta = Math.max(1 - alpha, (i + 1) / iterations);
relaxRightToLeft(columns, alpha, beta);
relaxLeftToRight(columns, alpha, beta);
}
}
// Reposition each node based on its incoming (target) links.
function relaxLeftToRight(columns, alpha, beta) {
for (let i = 1, n = columns.length; i < n; ++i) {
const column = columns[i];
for (const target of column) {
let y = 0;
let w = 0;
for (const {source, value} of target.targetLinks) {
let v = value * (target.layer - source.layer);
y += targetTop(source, target) * v;
w += v;
}
if (!(w > 0)) continue;
let dy = (y / w - target.y0) * alpha;
target.y0 += dy;
target.y1 += dy;
reorderNodeLinks(target);
}
if (sort === undefined) column.sort(ascendingBreadth);
resolveCollisions(column, beta);
}
}
// Reposition each node based on its outgoing (source) links.
function relaxRightToLeft(columns, alpha, beta) {
for (let n = columns.length, i = n - 2; i >= 0; --i) {
const column = columns[i];
for (const source of column) {
let y = 0;
let w = 0;
for (const {target, value} of source.sourceLinks) {
let v = value * (target.layer - source.layer);
y += sourceTop(source, target) * v;
w += v;
}
if (!(w > 0)) continue;
let dy = (y / w - source.y0) * alpha;
source.y0 += dy;
source.y1 += dy;
reorderNodeLinks(source);
}
if (sort === undefined) column.sort(ascendingBreadth);
resolveCollisions(column, beta);
}
}
function resolveCollisions(nodes, alpha) {
const i = nodes.length >> 1;
const subject = nodes[i];
resolveCollisionsBottomToTop(nodes, subject.y0 - py, i - 1, alpha);
resolveCollisionsTopToBottom(nodes, subject.y1 + py, i + 1, alpha);
resolveCollisionsBottomToTop(nodes, y1, nodes.length - 1, alpha);
resolveCollisionsTopToBottom(nodes, y0, 0, alpha);
}
// Push any overlapping nodes down.
function resolveCollisionsTopToBottom(nodes, y, i, alpha) {
for (; i < nodes.length; ++i) {
const node = nodes[i];
const dy = (y - node.y0) * alpha;
if (dy > 1e-6) node.y0 += dy, node.y1 += dy;
y = node.y1 + py;
}
}
// Push any overlapping nodes up.
function resolveCollisionsBottomToTop(nodes, y, i, alpha) {
for (; i >= 0; --i) {
const node = nodes[i];
const dy = (node.y1 - y) * alpha;
if (dy > 1e-6) node.y0 -= dy, node.y1 -= dy;
y = node.y0 - py;
}
}
function reorderNodeLinks({sourceLinks, targetLinks}) {
if (linkSort === undefined) {
for (const {source: {sourceLinks}} of targetLinks) {
sourceLinks.sort(ascendingTargetBreadth);
}
for (const {target: {targetLinks}} of sourceLinks) {
targetLinks.sort(ascendingSourceBreadth);
}
}
}
function reorderLinks(nodes) {
if (linkSort === undefined) {
for (const {sourceLinks, targetLinks} of nodes) {
sourceLinks.sort(ascendingTargetBreadth);
targetLinks.sort(ascendingSourceBreadth);
}
}
}
// Returns the target.y0 that would produce an ideal link from source to target.
function targetTop(source, target) {
let y = source.y0 - (source.sourceLinks.length - 1) * py / 2;
for (const {target: node, width} of source.sourceLinks) {
if (node === target) break;
y += width + py;
}
for (const {source: node, width} of target.targetLinks) {
if (node === source) break;
y -= width;
}
return y;
}
// Returns the source.y0 that would produce an ideal link from source to target.
function sourceTop(source, target) {
let y = target.y0 - (target.targetLinks.length - 1) * py / 2;
for (const {source: node, width} of target.targetLinks) {
if (node === source) break;
y += width + py;
}
for (const {target: node, width} of source.sourceLinks) {
if (node === target) break;
y -= width;
}
return y;
}
return sankey;
}
function horizontalSource(d) {
return [d.source.x1, d.y0];
}
function horizontalTarget(d) {
return [d.target.x0, d.y1];
}
function sankeyLinkHorizontal() {
return d3Shape.linkHorizontal()
.source(horizontalSource)
.target(horizontalTarget);
}
exports.sankey = Sankey;
exports.sankeyCenter = center;
exports.sankeyJustify = justify;
exports.sankeyLeft = left;
exports.sankeyLinkHorizontal = sankeyLinkHorizontal;
exports.sankeyRight = right;
Object.defineProperty(exports, '__esModule', { value: true });
}));

5
superx/xml/js/viz/d3.v3.min.js vendored

File diff suppressed because one or more lines are too long

518
superx/xml/js/viz/sankey_v3.js

@ -1,518 +0,0 @@
function makeSankey(targetDiv,data,metaData,chartElem)
{
var measureCaption = getMeasureCaption(chartElem,metaData); //"Studierende";
var captionEmptyTarget="Kein Master (eigene HS)";
var margin = {top: 10, right: 10, bottom: 10, left: 10},
width = 1200 - margin.left - margin.right,
height = 800 - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f"), // zero decimal places
format = function(d) { return measureCaption+": "+formatNumber(d); },
color = d3.scale.category20();
// append the svg canvas to the page
var clearCanvas=document.getElementById(targetDiv);
while (clearCanvas.firstChild) {
clearCanvas.removeChild(clearCanvas.firstChild);
}
//targetDiv
var svg = d3.select("#"+targetDiv).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(36)
.nodePadding(40)
.size([width, height]);
var path = sankey.link();
// load the data
var sNodes=getSankeyNodes(data,captionEmptyTarget); //graph.nodes;
var sLinks=getSankeyLinks(sNodes,data); //graph.links;
sankey
.nodes(sNodes)
.links(sLinks)
.layout(32);
// add in the links
var link = svg.append("g").selectAll(".link")
.data(sLinks)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
// add the link titles
link.append("title")
.text(function(d) {
return d.source.name + " → " +
d.target.name + "\n" + format(d.value); });
// add in the nodes
var node = svg.append("g").selectAll(".node")
.data(sNodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; })
/*.call(d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function() {
this.parentNode.appendChild(this); })
.on("drag", dragmove)
)*/
;
// add the rectangles for the nodes
node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) {
//return d.color = color(d.name.replace(/ .*/, ""));
//return d3.scaleLinear().domain([0,3,10]).range(["blue","white","red"]);
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
var col = "rgb(" + r + "," + g + "," + b + ")";
return d.color = col; //"red";
})
.style("stroke", function(d) {
return d3.rgb(d.color).darker(2); })
.append("title")
.text(function(d) {
return d.name + "\n" + format(d.value); });
// add in the title for the nodes
node.append("text")
.attr("x", -6)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.name; })
.filter(function(d) { return d.x < width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
}
function getSankeyNodes(data,captionEmptyTarget)
{
var myNodes=[];
var distinctSource = [];
var zs="";
for (var i = 0; i < data.length; i++)
{
if(zs.indexOf("_" + data[i].dimension1 +"_")<0)
{
distinctSource.push(data[i].dimension1);
zs+="_" + data[i].dimension1 +"_";
}
}
for (var i = 0; i < data.length; i++)
{
if(zs.indexOf("_" + data[i].dimension2 +"_")<0)
{
distinctSource.push(data[i].dimension2);
zs+="_" + data[i].dimension2 +"_";
}
}
for (var i = 0; i < distinctSource.length; i++)
{
myNodes[i] = { "node": i, "name": distinctSource[i] };
console.log("Abschluss: "+distinctSource[i]);
}
//Kein Abschluss:
myNodes[i] = { "node": i, "name": captionEmptyTarget };
return myNodes;
}
function getSankeyLinks(myNodes,data)
{
var myLinks=[];
var linkIndex=0;
for (var i = 0; i < data.length; i++)
{
if(data[i].dimension2 !="")
{
myLinks[linkIndex]={ "source": getSankeyNodeIndex(myNodes,data[i].dimension1),
"target": getSankeyNodeIndex(myNodes,data[i].dimension2), "value":data[i].measure1 };
linkIndex++;
}
else
{
myLinks[linkIndex]={ "source": getSankeyNodeIndex(myNodes,data[i].dimension1),
"target": myNodes.length-1, "value":data[i].measure1 };
linkIndex++;
}
}
return myLinks;
}
function getSankeyNodeIndex(myNodes,name)
{
var myIndex=0;
for (var i = 0; i < myNodes.length; i++)
{
if(myNodes[i].name==name)
myIndex=i
}
return myIndex;
}
function getMeasureCaption(chartElem,metaData)
{
var measureCaption="";
for(var k=0;k<chartElem.elementTypeProperties.length;k++)
{
if(chartElem.elementTypeProperties[k].propertyValue!="")
{
switch (chartElem.elementTypeProperties[k].vizTypePropertyUniquename)
{
case "viz_measure1":
measure1=chartElem.elementTypeProperties[k].propertyValue;
measureCaption=getMetadataOfVizTypeProperty(metaData,measure1);
if(measureCaption=="")
measureCaption=measure1;
break;
default:
break;
}
}
}
return measureCaption;
}
function getMetadataOfVizTypeProperty(metaData,vizTypePropertyUniquename)
{
var caption="";
for(var k=0;k<metaData.length;k++)
{
if(metaData[k].colname==vizTypePropertyUniquename)
{
caption=metaData[k].colcaption;
}
}
return caption;
}
// the function for moving the nodes for sankey
function dragmove(d) {
d3.select(this).attr("transform",
"translate(" + d.x + "," + (
d.y = Math.max(0, Math.min(d3.select(this).attr("height") - d.dy, d3.event.y))
) + ")");
sankey.relayout();
link.attr("d", path);
}
d3.sankey = function() {
var sankey = {},
nodeWidth = 24,
nodePadding = 8,
size = [1, 1],
nodes = [],
links = [];
sankey.nodeWidth = function(_) {
if (!arguments.length) return nodeWidth;
nodeWidth = +_;
return sankey;
};
sankey.nodePadding = function(_) {
if (!arguments.length) return nodePadding;
nodePadding = +_;
return sankey;
};
sankey.nodes = function(_) {
if (!arguments.length) return nodes;
nodes = _;
return sankey;
};
sankey.links = function(_) {
if (!arguments.length) return links;
links = _;
return sankey;
};
sankey.size = function(_) {
if (!arguments.length) return size;
size = _;
return sankey;
};
sankey.layout = function(iterations) {
computeNodeLinks();
computeNodeValues();
computeNodeBreadths();
computeNodeDepths(iterations);
computeLinkDepths();
return sankey;
};
sankey.relayout = function() {
computeLinkDepths();
return sankey;
};
sankey.link = function() {
var curvature = .5;
function link(d) {
var x0 = d.source.x + d.source.dx,
x1 = d.target.x,
xi = d3.interpolateNumber(x0, x1),
x2 = xi(curvature),
x3 = xi(1 - curvature),
y0 = d.source.y + d.sy + d.dy / 2,
y1 = d.target.y + d.ty + d.dy / 2;
return "M" + x0 + "," + y0
+ "C" + x2 + "," + y0
+ " " + x3 + "," + y1
+ " " + x1 + "," + y1;
}
link.curvature = function(_) {
if (!arguments.length) return curvature;
curvature = +_;
return link;
};
return link;
};
// Populate the sourceLinks and targetLinks for each node.
// Also, if the source and target are not objects, assume they are indices.
function computeNodeLinks() {
nodes.forEach(function(node) {
node.sourceLinks = [];
node.targetLinks = [];
});
links.forEach(function(link) {
var source = link.source,
target = link.target;
console.log("source: "+source+" TARGET: "+target);
if (typeof source === "number" || typeof source === "string") source = link.source = nodes[link.source];
if (typeof target === "number" || typeof target === "string") target = link.target = nodes[link.target];
source.sourceLinks.push(link);
target.targetLinks.push(link);
});
}
// Compute the value (size) of each node by summing the associated links.
function computeNodeValues() {
nodes.forEach(function(node) {
node.value = Math.max(
d3.sum(node.sourceLinks, value),
d3.sum(node.targetLinks, value)
);
});
}
// Iteratively assign the breadth (x-position) for each node.
// Nodes are assigned the maximum breadth of incoming neighbors plus one;
// nodes with no incoming links are assigned breadth zero, while
// nodes with no outgoing links are assigned the maximum breadth.
function computeNodeBreadths() {
var remainingNodes = nodes,
nextNodes,
x = 0;
while (remainingNodes.length) {
nextNodes = [];
remainingNodes.forEach(function(node) {
node.x = x;
node.dx = nodeWidth;
node.sourceLinks.forEach(function(link) {
nextNodes.push(link.target);
});
});
remainingNodes = nextNodes;
++x;
}
//
moveSinksRight(x);
scaleNodeBreadths((size[0] - nodeWidth) / (x - 1));
}
function moveSourcesRight() {
nodes.forEach(function(node) {
if (!node.targetLinks.length) {
node.x = d3.min(node.sourceLinks, function(d) { return d.target.x; }) - 1;
}
});
}
function moveSinksRight(x) {
nodes.forEach(function(node) {
if (!node.sourceLinks.length) {
node.x = x - 1;
}
});
}
function scaleNodeBreadths(kx) {
nodes.forEach(function(node) {
node.x *= kx;
});
}
function computeNodeDepths(iterations) {
var nodesByBreadth = d3.nest()
.key(function(d) { return d.x; })
.sortKeys(d3.ascending)
.entries(nodes)
.map(function(d) { return d.values; });
//
initializeNodeDepth();
resolveCollisions();
for (var alpha = 1; iterations > 0; --iterations) {
relaxRightToLeft(alpha *= .99);
resolveCollisions();
relaxLeftToRight(alpha);
resolveCollisions();
}
function initializeNodeDepth() {
var ky = d3.min(nodesByBreadth, function(nodes) {
return (size[1] - (nodes.length - 1) * nodePadding) / d3.sum(nodes, value);
});
nodesByBreadth.forEach(function(nodes) {
nodes.forEach(function(node, i) {
node.y = i;
node.dy = node.value * ky;
});
});
links.forEach(function(link) {
link.dy = link.value * ky;
});
}
function relaxLeftToRight(alpha) {
nodesByBreadth.forEach(function(nodes, breadth) {
nodes.forEach(function(node) {
if (node.targetLinks.length) {
var y = d3.sum(node.targetLinks, weightedSource) / d3.sum(node.targetLinks, value);
node.y += (y - center(node)) * alpha;
}
});
});
function weightedSource(link) {
return center(link.source) * link.value;
}
}
function relaxRightToLeft(alpha) {
nodesByBreadth.slice().reverse().forEach(function(nodes) {
nodes.forEach(function(node) {
if (node.sourceLinks.length) {
var y = d3.sum(node.sourceLinks, weightedTarget) / d3.sum(node.sourceLinks, value);
node.y += (y - center(node)) * alpha;
}
});
});
function weightedTarget(link) {
return center(link.target) * link.value;
}
}
function resolveCollisions() {
nodesByBreadth.forEach(function(nodes) {
var node,
dy,
y0 = 0,
n = nodes.length,
i;
// Push any overlapping nodes down.
nodes.sort(ascendingDepth);
for (i = 0; i < n; ++i) {
node = nodes[i];
dy = y0 - node.y;
if (dy > 0) node.y += dy;
y0 = node.y + node.dy + nodePadding;
}
// If the bottommost node goes outside the bounds, push it back up.
dy = y0 - nodePadding - size[1];
if (dy > 0) {
y0 = node.y -= dy;
// Push any overlapping nodes back up.
for (i = n - 2; i >= 0; --i) {
node = nodes[i];
dy = node.y + node.dy + nodePadding - y0;
if (dy > 0) node.y -= dy;
y0 = node.y;
}
}
});
}
function ascendingDepth(a, b) {
return a.y - b.y;
}
}
function computeLinkDepths() {
nodes.forEach(function(node) {
node.sourceLinks.sort(ascendingTargetDepth);
node.targetLinks.sort(ascendingSourceDepth);
});
nodes.forEach(function(node) {
var sy = 0, ty = 0;
node.sourceLinks.forEach(function(link) {
link.sy = sy;
sy += link.dy;
});
node.targetLinks.forEach(function(link) {
link.ty = ty;
ty += link.dy;
});
});
function ascendingSourceDepth(a, b) {
return a.source.y - b.source.y;
}
function ascendingTargetDepth(a, b) {
return a.target.y - b.target.y;
}
}
function center(node) {
return node.y + node.dy / 2;
}
function value(link) {
return link.value;
}
return sankey;
};

253
superx/xml/js/viz/viz_functions.js

@ -34,6 +34,7 @@ const chartModel={
} }
*/ */
function chartModel(id,name,renderer,datasources) function chartModel(id,name,renderer,datasources)
{ {
this.version="0.2b"; this.version="0.2b";
@ -556,9 +557,9 @@ function createChartElementConfig1Form(renderer,elemID)
labelVizType.classList.add("is-required"); labelVizType.classList.add("is-required");
labelVizType.classList.add("is-small"); labelVizType.classList.add("is-small");
labelVizType.classList.add("has-tooltip-right"); labelVizType.classList.add("has-tooltip-right");
labelVizType.setAttribute("data-tooltip","Art des Diagrammelements"); labelVizType.setAttribute("data-tooltip","Art des Grafikelements");
const textnodeVizType = document.createTextNode("Diagrammelement-Typ"); const textnodeVizType = document.createTextNode("Grafikelement-Typ");
labelVizType.appendChild(textnodeVizType); labelVizType.appendChild(textnodeVizType);
labelVizTypeElem.appendChild(labelVizType); labelVizTypeElem.appendChild(labelVizType);
fieldVizTypeElem.appendChild(labelVizTypeElem); fieldVizTypeElem.appendChild(labelVizTypeElem);
@ -920,12 +921,12 @@ function filld3data(myRs,MyRsMetaData,chartElem)
{ {
switch (chartElem.elementTypeProperties[k].vizTypePropertyUniquename) switch (chartElem.elementTypeProperties[k].vizTypePropertyUniquename)
{ {
case "viz_dimension1": case "dimension1":
dimension1=chartElem.elementTypeProperties[k].propertyValue; dimension1=chartElem.elementTypeProperties[k].propertyValue;
case "viz_dimension2": case "dimension2":
dimension2=chartElem.elementTypeProperties[k].propertyValue; dimension2=chartElem.elementTypeProperties[k].propertyValue;
break; break;
case "viz_measure1": case "measure1":
measure1=chartElem.elementTypeProperties[k].propertyValue; measure1=chartElem.elementTypeProperties[k].propertyValue;
break; break;
default: default:
@ -1778,6 +1779,8 @@ function getVizTypeOrientation(vizTypeUniquename)
} }
function renderChartElementWithD3(chartElem,targetDiv) function renderChartElementWithD3(chartElem,targetDiv)
{ {
d3.select("#"+targetDiv).selectAll("svg").selectAll("g").remove();
d3.select("#"+targetDiv).selectAll("svg").selectAll("rect").remove();
var mySvg= d3.select("#"+targetDiv).selectAll("svg");//.append("svg"); var mySvg= d3.select("#"+targetDiv).selectAll("svg");//.append("svg");
if(chartElem) if(chartElem)
{ {
@ -1790,6 +1793,9 @@ switch (chartType)
case "bar_x_d3": case "bar_x_d3":
mySvg=makeBarX_d3(mySvg,data,chartElem); mySvg=makeBarX_d3(mySvg,data,chartElem);
break; break;
case "sankey":
mySvg=makeSankeyD3(mySvg,data,rsColumnMetaData[chartElem.datasource],chartElem);
break;
default: default:
alert("Unknown chart type"); alert("Unknown chart type");
break; break;
@ -2311,7 +2317,20 @@ function getChartPropertyValue(propArray,propName)
function getCommonChartProperty(name) function getCommonChartProperty(name)
{ {
var propertyValue=""; var propertyValue="";
for (var i=0;i<commonChartProperties.length;i++) if(document.forms["chartPropertiesForm"].elements[name])
{
propertyValue=document.forms["chartPropertiesForm"].elements[name].value;
}
if(propertyValue=="")
{
let prop = commonChartProperties.find(o => o.name === name);
if(prop.defaultValue!="")
{
propertyValue=prop.defaultValue;
}
}
/*for (var i=0;i<commonChartProperties.length;i++)
{ {
if(commonChartProperties[i].name==name && document.forms["chartPropertiesForm"].elements[name]) if(commonChartProperties[i].name==name && document.forms["chartPropertiesForm"].elements[name])
{ {
@ -2321,7 +2340,7 @@ function getCommonChartProperty(name)
propertyValue=commonChartProperties[i].defaultValue; propertyValue=commonChartProperties[i].defaultValue;
} }
} }
} }*/
return propertyValue; return propertyValue;
} }
function showSrcCode(renderer) function showSrcCode(renderer)
@ -2579,3 +2598,223 @@ for (let i = 1; i < 4; i++) {
} }
} }
function makeSankeyD3(mySvg,data,metaData,chartElem)
{
// load the data
var captionEmptyTarget="Kein Abschluss";
var sNodes=getSankeyNodes(data,captionEmptyTarget); //graph.nodes;
var sLinks=getSankeyLinks(sNodes,data); //graph.links;
renderSankey(mySvg,sNodes,sLinks);
//var myChartSVG = SankeyChart(sNodes,sLinks);
}
function getSankeyNodes(data,captionEmptyTarget)
{
var myNodes=[];
var distinctSource = [];
var zs="";
for (var i = 0; i < data.length; i++)
{
if(zs.indexOf("_" + data[i].dimension1 +"_")<0)
{
distinctSource.push(data[i].dimension1);
zs+="_" + data[i].dimension1 +"_";
}
}
for (var i = 0; i < data.length; i++)
{
if(zs.indexOf("_" + data[i].dimension2 +"_")<0)
{
distinctSource.push(data[i].dimension2);
zs+="_" + data[i].dimension2 +"_";
}
}
for (var i = 0; i < distinctSource.length; i++)
{
myNodes[i] = { "node": i, "name": distinctSource[i] };
console.log("Abschluss: "+distinctSource[i]);
}
//Kein Abschluss:
myNodes[i] = { "node": i, "name": captionEmptyTarget };
return myNodes;
}
function getSankeyLinks(myNodes,data)
{
var myLinks=[];
var linkIndex=0;
for (var i = 0; i < data.length; i++)
{
if(data[i].dimension2 !="")
{
myLinks[linkIndex]={ "source": getSankeyNodeIndex(myNodes,data[i].dimension1),
"target": getSankeyNodeIndex(myNodes,data[i].dimension2), "value":data[i].measure1 };
linkIndex++;
}
else
{
myLinks[linkIndex]={ "source": getSankeyNodeIndex(myNodes,data[i].dimension1),
"target": myNodes.length-1, "value":data[i].measure1 };
linkIndex++;
}
}
return myLinks;
}
function getSankeyNodeIndex(myNodes,name)
{
var myIndex=0;
for (var i = 0; i < myNodes.length; i++)
{
if(myNodes[i].name==name)
myIndex=i
}
return myIndex;
}
function getMeasureCaption(chartElem,metaData)
{
var measureCaption="";
for(var k=0;k<chartElem.elementTypeProperties.length;k++)
{
if(chartElem.elementTypeProperties[k].propertyValue!="")
{
switch (chartElem.elementTypeProperties[k].vizTypePropertyUniquename)
{
case "viz_measure1":
measure1=chartElem.elementTypeProperties[k].propertyValue;
measureCaption=getMetadataOfVizTypeProperty(metaData,measure1);
if(measureCaption=="")
measureCaption=measure1;
break;
default:
break;
}
}
}
return measureCaption;
}
function getMetadataOfVizTypeProperty(metaData,vizTypePropertyUniquename)
{
var caption="";
for(var k=0;k<metaData.length;k++)
{
if(metaData[k].colname==vizTypePropertyUniquename)
{
caption=metaData[k].colcaption;
}
}
return caption;
}
function renderSankey(svg,sNodes,sLinks)
{
// set the dimensions and margins of the graph
var margin = { top: 10, right: 10, bottom: 10, left: 10 },
//var margin = { top: 0, right: 50, bottom: 0, left: 0 },
width = getCommonChartProperty("width") - margin.left - margin.right,
height = getCommonChartProperty("height") - margin.top - margin.bottom;
// format variables
var formatNumber = d3.format(",.0f"), // zero decimal places
format = function (d) { return formatNumber(d); },
color = d3.scaleOrdinal().range(["#002060ff", "#164490ff", "#4d75bcff", "#98b3e6ff", "#d5e2feff", "#008cb0ff"]);
// append the svg object to the body of the page
/*const sankeyDiv = svg.selectAll("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
*/
// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(100)
.nodePadding(40)
.size([width, height]);
var path = sankey.links();
var data=new Object;
data.nodes=sNodes;
data.links=sLinks;
var graph=sankey(data);
// add in the links
var link = svg.append("g").selectAll(".link")
.data(graph.links)
.enter().append("path")
.attr("class", "link")
.attr("d", d3.sankeyLinkHorizontal())
.attr("stroke-width", function (d) { return d.width; });
// add the link titles
link.append("title")
.text(function (d) {
return d.source.name + " → " +
d.target.name+": "+d.value;
});
// add in the nodes
var node = svg.append("g").selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
// add the rectangles for the nodes
node.append("rect")
.attr("x", function (d) { return d.x0; })
.attr("y", function (d) { return d.y0; })
.attr("height", function (d) { return d.y1 - d.y0; })
.attr("width", sankey.nodeWidth())
.style("fill", function (d) {
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
var col = "rgb(" + r + "," + g + "," + b + ")";
return d.color = col;
})
// Attempt at getting whole length of link to highlight
.on("mouseover", function (d) {
link
.transition()
.duration(300)
.style("stroke-opacity", function (l) {
return l.source === d || l.target === d ? 0.5 : 0.2;
});
})
.on("mouseleave", function (d) {
link
.transition()
.duration(300)
.style("stroke-opacity", 0.2);
})
// Node hover titles
.append("title")
.text(function (d) {
return d.name + "\n" + format(d.value);
});
// add in the title for the nodes
node.append("text")
.style("fill", "#3f3f3f")
.attr("x", function (d) { return d.x0 - 6; })
.attr("y", function (d) { return (d.y1 + d.y0) / 2; })
.attr("dy", "0.35em")
.attr("text-anchor", "end")
.text(function (d) { return d.name; })
.filter(function (d) { return d.x0 < width / 2; })
.attr("x", function (d) { return d.x1 + 6; })
.attr("text-anchor", "start")
;
}

6
superx/xml/viz_html_chart.xsl

@ -20,7 +20,6 @@ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:HtmlUtils="de.superx.util
<xsl:variable name="defaultRenderer" select="'plot'" /> <xsl:variable name="defaultRenderer" select="'plot'" />
<xsl:variable name="availableRendererPlot" select="'true'" /> <xsl:variable name="availableRendererPlot" select="'true'" />
<xsl:variable name="availableRendererD3" select="'true'" /> <xsl:variable name="availableRendererD3" select="'true'" />
<xsl:variable name="availableRendererD3V3" select="'false'" />
<xsl:template match="/"> <xsl:template match="/">
<xsl:call-template name="table"/> <xsl:call-template name="table"/>
</xsl:template> </xsl:template>
@ -77,8 +76,10 @@ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:HtmlUtils="de.superx.util
<xsl:template name="importVizJavascriptLibs"> <xsl:template name="importVizJavascriptLibs">
<script language="Javascript" type="text/javascript" src="../xml/js/viz/d3.min.js" /> <script language="Javascript" type="text/javascript" src="../xml/js/viz/d3.min.js" />
<script language="Javascript" type="text/javascript" src="../xml/js/viz/plot.js" /> <script language="Javascript" type="text/javascript" src="../xml/js/viz/plot.js" />
<script language="Javascript" type="module" src="../xml/js/viz/d3-sankey.js" />
<xsl:for-each select="/ergebnisse/ergebnis/ergebniselement/vizTypes/vizType[@srcpath !='/superx/xml/js/viz/d3.min.js' <xsl:for-each select="/ergebnisse/ergebnis/ergebniselement/vizTypes/vizType[@srcpath !='/superx/xml/js/viz/d3.min.js'
and @srcpath != '/superx/xml/js/viz/plot.js' and @srcpath != '/superx/xml/js/viz/plot.js'
and @srcpath != '/superx/xml/js/viz/sankey.js'
and @srcpath != '' and @srcpath != ''
and (@renderer_uniquename='plot' or @renderer_uniquename='d3js') ]"> and (@renderer_uniquename='plot' or @renderer_uniquename='d3js') ]">
<script language="Javascript" type="text/javascript" src="{@srcpath}" /> <script language="Javascript" type="text/javascript" src="{@srcpath}" />
@ -895,9 +896,6 @@ rs[</xsl:text><xsl:value-of select="$tableId"/><xsl:text>].push(new dataRow_</xs
<xsl:if test="$availableRendererD3='true'"> <xsl:if test="$availableRendererD3='true'">
<option class="maskinput" value="d3js" >D3JS</option> <option class="maskinput" value="d3js" >D3JS</option>
</xsl:if> </xsl:if>
<xsl:if test="$availableRendererD3V3='true'">
<option class="maskinput" value="d3jsv3" >D3JS (Version 3)</option>
</xsl:if>
</select> </select>
</div> </div>

Loading…
Cancel
Save