Browse Source

Erster Entwurf Sankey Chart #6

viz_worldmap
Daniel Quathamer 2 years ago
parent
commit
732a3b84ea
  1. 6
      src-modules/module/viz/conf/includes.txt
  2. 15
      src-modules/module/viz/schluesseltabellen/sx_stylesheets_einfuegen.sql
  3. 5
      src-modules/module/viz/schluesseltabellen/viz_property.unl
  4. 2
      src-modules/module/viz/schluesseltabellen/viz_type.unl
  5. 5
      src-modules/module/viz/schluesseltabellen/viz_type_property.unl
  6. 5
      superx/xml/js/viz/d3.v3.min.js
  7. 556
      superx/xml/js/viz/sankey_v3.js
  8. 359
      superx/xml/js/viz/viz_functions.js
  9. 25
      superx/xml/viz_html_chart.xsl
  10. 34
      superx/xml/viz_html_chart_sankey.xsl

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

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

15
src-modules/module/viz/schluesseltabellen/sx_stylesheets_einfuegen.sql

@ -4,7 +4,8 @@ @@ -4,7 +4,8 @@
<#assign masken = [
{"mask":"16000", "filename":"tabelle_html_datenblatt.xsl", "ord":"1"},
{"mask":"16000", "filename":"viz_html_chart.xsl", "ord":"100"}
{"mask":"16000", "filename":"viz_html_chart.xsl", "ord":"100"},
{"mask":"30220", "filename":"viz_html_chart_sankey.xsl", "ord":"120"}
] />
<#assign stylesheet = [
@ -14,12 +15,18 @@ @@ -14,12 +15,18 @@
"relation":"table",
"contenttype":"text/html",
"is_generic":"1"
}
},
{"filename":"viz_html_chart_sankey.xsl", "caption":"Übergangsdiagramm (Sankey-Diagramm)", "description":"Kreuztabelle Studienanfänger MA und vorheriger BA", "relation":"table", "contenttype":"text/html","is_generic":"0"}
] />
<#assign stylesheet_field = [
{"filename":"viz_html_chart_sankey.xsl", "tablename":"erfolg_ba_ma_uebergang", "fieldname":"abschluss_vorher_abschluss"},
{"filename":"viz_html_chart_sankey.xsl", "tablename":"erfolg_ba_ma_uebergang", "fieldname":"abschluss_vorher_abschlussart"},
{"filename":"viz_html_chart_sankey.xsl", "tablename":"erfolg_ba_ma_uebergang", "fieldname":"abschluss_vorher_abschlusstyp"},
{"filename":"viz_html_chart_sankey.xsl", "tablename":"erfolg_ba_ma_uebergang", "fieldname":"einschr_nachher_abschlussart"},
{"filename":"viz_html_chart_sankey.xsl", "tablename":"erfolg_ba_ma_uebergang", "fieldname":"einschr_nachher_abschluss"},
{"filename":"viz_html_chart_sankey.xsl", "tablename":"erfolg_ba_ma_uebergang", "fieldname":"einschr_nachher_abschlusstyp"},
{"filename":"viz_html_chart_sankey.xsl", "tablename":"erfolg_ba_ma_uebergang", "fieldname":"summe"}
] />
--Hier eventuell notwendige delete's auf die Tabellen sx_mask_style, sx_stylesheets oder stylesheet_field einfügen.

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

@ -31,9 +31,9 @@ @@ -31,9 +31,9 @@
68^Maß: Chart-Abstand^gridChartOffset^^ ^1^ ^0^1^18^ ^607^^^string^
69^Maß: Label-Höhe^gridLabelHeight^^px^1^ ^0^1^18^ ^608^^^integer^
70^X-Achse^x^^ ^1^ ^0^1^5^ ^608^^^string^
71^Kategorie-Dimension 2^viz_dimension2^^ ^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^
73^Maß 2^viz_measure2^^ ^1^ ^0^1^6^ ^608^^^string^
73^Maß 1^viz_measure1^^ ^1^ ^0^1^6^ ^608^^^string^
76^Serien-Dimension^stroke^^ ^1^ ^0^1^5^ ^608^^^string^
78^Legende^legend^^ ^1^true|false^0^2^20^ ^303^^^boolean^
79^Textbeschriftung^text^^ ^1^ ^0^1^5^ ^608^^^string^
@ -47,3 +47,4 @@ @@ -47,3 +47,4 @@
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^
89^Sortierung^sort^^ ^1^ ^0^1^5^ ^608^^^string^
90^Kategorie-Dimension 2^viz_dimension2^^ ^1^ ^0^1^5^ ^608^^^string^

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

@ -7,3 +7,5 @@ @@ -7,3 +7,5 @@
8^area_x^Flächen (horizontal)^2^^^
9^box_y^Boxplot (vertikal)^2^ ^ ^
10^text^Wertelabel^2^ ^ ^
11^bar_x_d3^Balken (horizontal)^1^^^
12^sankey^Sankey^1^/superx/xml/js/viz/sankey.js^^

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

@ -31,3 +31,8 @@ @@ -31,3 +31,8 @@
41^10^70^1^
42^10^72^1^
43^10^79^1^
44^11^71^1^
45^11^73^1^
46^12^71^1^
47^12^73^1^
48^12^76^1^

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

File diff suppressed because one or more lines are too long

556
superx/xml/js/viz/sankey_v3.js

@ -0,0 +1,556 @@ @@ -0,0 +1,556 @@
/*
myNodes[0] = { "node": 0, "name": "Africa" };
myNodes[1] = { "node": 1, "name": "America" };
myNodes[2] = { "node": 2, "name": "Europe" };
myLinks[0] = { "source": 0, "target": 2, "value":1 };
myLinks[1] = { "source": 1, "target": 2, "value":20 };
let my_object1 = {};
my_object1.name = "Africa";
my_object1.node = 0;
myNodes.push(my_object1);
//let my_object2 = {};
my_object1.name = "America";
my_object1.node = 1;
myNodes.push(new Objectmy_object1);
let my_object3 = {};
my_object3.name = "Europe";
my_object3.node = 2;
myNodes.push(my_object3);
let my_Linkobject1 = {};
my_Linkobject1.source = 0;
my_Linkobject1.target = 2;
my_Linkobject1.value = 1;
myLinks.push(my_Linkobject1);
let my_Linkobject2 = {};
my_Linkobject2.source = 1;
my_Linkobject2.target = 2;
my_Linkobject2.value = 20;
myLinks.push(my_Linkobject2);
*/
/*var newNode = new myNode("0","Africa");
myNodes.push(myNode);
var newNode = new myNode("1","America");
myNodes.push(myNode);
var newNode = new myNode("2","Europe");
myNodes.push(myNode);
var newLink = new myLink("0","2",1);
myLinks.push(newLink);
var newLink = new myLink("1","2",2);
myLinks.push(newLink);
*/
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 = 700 - margin.left - margin.right,
height = 300 - 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("chartDiv");
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(/ .*/, "")); })
.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(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;
};

359
superx/xml/js/viz/viz_functions.js

@ -41,10 +41,9 @@ function chartModel(id,name,renderer,datasources) @@ -41,10 +41,9 @@ function chartModel(id,name,renderer,datasources)
this.renderer=renderer;
this.dataSources=datasources;
//this.globalProperties=globalproperties;
this.targetDiv=""; //only for d3
this.chartElements=new Array();
this.options=new Object;
this.options.marks=new Array();
this.options.sort=new Array();
this.chartPropertiesUsed=new Array();
//let globalProperties={};
this.getChartSVG = function () {
@ -55,21 +54,55 @@ function chartModel(id,name,renderer,datasources) @@ -55,21 +54,55 @@ function chartModel(id,name,renderer,datasources)
case "plot":
mySVG=this.getChartSVGWithPlot();
break;
case "d3js":
mySVG=this.getChartSVGWithD3();
break;
case "d3jsv3":
mySVG=this.getChartSVGWithD3V3();
break;
default:
alert("No renderer");
break;
}
return mySVG;
}
this.renderChartSVG = function () {
//console.log(JSON.stringify(this));
var mySVG="";
switch (this.renderer) {
case "plot":
mySVG=this.getChartSVGWithPlot();
break;
case "d3js":
mySVG=this.getChartSVGWithD3();
break;
case "d3jsv3":
this.renderChartSVGWithD3V3();
break;
default:
alert("No renderer");
break;
}
return true;
}
this.getChartSVGWithPlot=function ()
{
console.log("using Plot");
var myOptions=new Object;
//myOptions.marks=new Array();
//myOptions.sort=new Array();
myOptions=getPlotOptionsObj(this.chartPropertiesUsed);
var marksArray=new Array();
/*for(var k=0;k< myChartModel.chartPropertiesUsed.length;k++)
{
}*/
//first empty marks:
for(var k=0;k< this.options["marks"].length;k++)
for(var k=0;k< myOptions["marks"].length;k++)
{
this.options["marks"][k].pop();
myOptions["marks"][k].pop();
}
//copy ChartElements to marks:
for(var k=0;k< this.chartElements.length;k++)
@ -85,10 +118,32 @@ function chartModel(id,name,renderer,datasources) @@ -85,10 +118,32 @@ function chartModel(id,name,renderer,datasources)
}
this.options["marks"].push(marksArray);
var svgPlot=Plot.plot(this.options);
myOptions["marks"].push(marksArray);
var svgPlot=Plot.plot(myOptions);
return svgPlot;
}
this.getChartSVGWithD3=function ()
{
console.log("using D3JS");
var svgD3=new Object;
for(var k=0;k< this.chartElements.length;k++)
{
svgD3=renderChartElementWithD3(this.chartElements[k]);
}
return svgD3;
}
this.renderChartSVGWithD3V3=function ()
{
console.log("using D3JS_v3");
var svgD3=new Object;
for(var k=0;k< this.chartElements.length;k++)
{
svgD3=renderChartElementWithD3V3(this.chartElements[k],this.targetDiv);
}
return svgD3;
}
}
@ -114,6 +169,13 @@ this.datasource=datasource; @@ -114,6 +169,13 @@ this.datasource=datasource;
this.elementTypeProperties=new Array();
}
function usedVizProperty(name,vizPropertyVariablename,propertyValue )
{
this.name=name;
this.vizPropertyVariablename=vizPropertyVariablename;
this.propertyValue=propertyValue;
}
function usedVizTypeProperty(nr,vizTypePropertyUniquename,caption,propertyValue )
{
this.nr=nr;
@ -123,12 +185,12 @@ this.propertyValue=propertyValue; @@ -123,12 +185,12 @@ this.propertyValue=propertyValue;
}
function d3dataRow(nr,dimension1,dimension2,measure )
function d3dataRow(nr,dimension1,dimension2,measure1 )
{
this.nr=nr;
this.dimension1=dimension1;
this.dimension2=dimension2;
this.measure=measure;
this.measure1=measure1;
}
@ -243,22 +305,73 @@ this.getValueResultset = function () { @@ -243,22 +305,73 @@ this.getValueResultset = function () {
}
}
/*Transfer form to model: */
function updateChartModel()
{
var optionsString="{";
var myChartPropertiesUsed=new Array();
//first empty properties:
/*for(var k=0;k< myChartModel.chartPropertiesUsed.length;k++)
{
myChartModel.chartPropertiesUsed[k].pop();
}*/
if(document.getElementById("chartName").value=="")
document.getElementById("chartName").value=vizInitialName;
var chartName=document.getElementById("chartName").value;
//myChartModel.options.caption=chartName;
if(myChartModel.renderer=="")
myChartModel.renderer=document.getElementById("fldVizRenderer").value;
optionsString+="\"caption\":\""+chartName+"\"";
var myCaption=new usedVizProperty("caption","caption",chartName);
myChartPropertiesUsed.push(myCaption);
//var myForm=document.forms["chartPropertiesForm"];
for(var k=0;k < commonChartProperties.length;k++)
{
if(getCommonChartProperty(commonChartProperties[k].name)!="")
{
var myProp=new usedVizProperty(commonChartProperties[k].name,commonChartProperties[k].variableName,getCommonChartProperty(commonChartProperties[k].name));
myChartPropertiesUsed.push(myProp);
}
}
var myForm=document.forms["chartPropertiesForm"];
//first Collect all groups:
myChartModel.chartPropertiesUsed=myChartPropertiesUsed;
/*
var stylesString="{\"overflow\": \"visible\"";
for(var k=0;k < commonChartProperties.length;k++)
{
if(commonChartProperties[k].groupUniquename=="STYLE" )
{
stylesString+=",\""+commonChartProperties[k].variableName+"\":\""+getCommonChartProperty(commonChartProperties[k].name)+"\"";
}
}
stylesString+=" }";
console.log("Styles:"+ stylesString);
var styles=JSON.parse(stylesString); */
//console.log("options:"+ optionsString);
//var globalProperties=JSON.parse(optionsString);
//globalProperties["marks"].push(marksArray);
//myChartModel.options=globalProperties;
//myChartModel.options["marks"].push(marksArray);
return myChartModel;
}
function getPlotOptionsObj(chartPropertiesUsed)
{
var commonChartPropertyGroups=[];
var previousGroup="";
var optionsString="{";
optionsString+="\"caption\":\""+getChartPropertyValue(chartPropertiesUsed,"caption")+"\"";
for(var k=0;k < commonChartProperties.length;k++)
{
var groupVariableName=commonChartProperties[k].groupVariableName;
@ -281,61 +394,21 @@ function updateChartModel() @@ -281,61 +394,21 @@ function updateChartModel()
if(commonChartProperties[k].groupVariableName==commonChartPropertyGroups[i].groupVariableName
&& commonChartProperties[k].variableName!=""
&& getCommonChartProperty(commonChartProperties[k].name)!="")
&& getChartPropertyValue(chartPropertiesUsed,commonChartProperties[k].name)!="")
{
textDelim=(commonChartProperties[k].propValueType=="string")?"\"":"";
optionsString+=",\""+commonChartProperties[k].variableName+"\":"+textDelim+getCommonChartProperty(commonChartProperties[k].name)+textDelim;
optionsString+=",\""+commonChartProperties[k].variableName+"\":"+textDelim+getChartPropertyValue(chartPropertiesUsed,commonChartProperties[k].name)+textDelim;
}
}
if(commonChartPropertyGroups[i].groupVariableName!="layout")
optionsString+=" }"; //close tag
}
/*
for(var k=0;k < commonChartProperties.length;k++)
{
for(var i=0;i < myForm.elements.length;i++)
{
if(commonChartProperties[k].name==myForm.elements[i].name
&&myForm.elements[i].value!="")
{
console.log("Feld ausgefüllt:" +commonChartProperties[k].name);
textDelim=(commonChartProperties[k].propValueType=="string")?"\"":"";
optionsString+=",\""+commonChartProperties[k].variableName+"\":"+textDelim+myForm.elements[i].value+textDelim;
}
}
}*/
optionsString+= ", \"marks\":[]";
optionsString+=" }"; //close tag
/*
var stylesString="{\"overflow\": \"visible\"";
for(var k=0;k < commonChartProperties.length;k++)
{
if(commonChartProperties[k].groupUniquename=="STYLE" )
{
stylesString+=",\""+commonChartProperties[k].variableName+"\":\""+getCommonChartProperty(commonChartProperties[k].name)+"\"";
}
}
stylesString+=" }";
console.log("Styles:"+ stylesString);
var styles=JSON.parse(stylesString); */
var chartOptions=JSON.parse(optionsString);
return chartOptions;
myChartModel.options=chartOptions;
//console.log("options:"+ optionsString);
//var globalProperties=JSON.parse(optionsString);
//globalProperties["marks"].push(marksArray);
//myChartModel.options=globalProperties;
//myChartModel.options["marks"].push(marksArray);
return myChartModel;
}
function renderChart(chartDiv,currentChartModel)
{
@ -344,15 +417,26 @@ function renderChart(chartDiv,currentChartModel) @@ -344,15 +417,26 @@ function renderChart(chartDiv,currentChartModel)
document.getElementById("chartName").value=vizInitialName;
if(currentChartModel.chartElements.length>0 && currentChartModel.chartElements[0])
{
if(currentChartModel.renderer=="plot")
{
var mySVG=currentChartModel.getChartSVG();
if(typeof mySVG === 'object')
{
document.getElementById(chartDiv).innerHTML="";
document.getElementById(chartDiv).appendChild(mySVG);
}
}
else
{
//d3js:
currentChartModel.targetDiv=chartDiv;
currentChartModel.renderChartSVG();
}
}
else
document.getElementById(chartDiv).innerHTML="<svg viewBox=\"0 0 650 450\"><rect x=\"0\" y=\"0\" width=\"650\" height=\"450\" fill=\"#cccccc\"></rect></svg>";
document.getElementById(chartDiv).innerHTML="<svg style=\"width:100%;height: auto;\" viewBox=\"0 0 800 600\" width=\"800\" height=\"600\"></svg>";
//"<rect x=\"0\" y=\"0\" width=\"800\" height=\"450\" fill=\"#cccccc\"></rect>";
//
}
@ -781,9 +865,81 @@ function fillSelectionResultMetaData() @@ -781,9 +865,81 @@ function fillSelectionResultMetaData()
return selectionRsMetaData;
}
function fillSelectionResult(selectionRsMetaData)
function filld3data(myRs,MyRsMetaData,chartElem)
{
//Identify dimensions and measures:
var dimension1,dimension2,measure1;
var data=[];
for(var k=0;k<chartElem.elementTypeProperties.length;k++)
{
if(chartElem.elementTypeProperties[k].propertyValue!="")
{
switch (chartElem.elementTypeProperties[k].vizTypePropertyUniquename)
{
case "viz_dimension1":
dimension1=chartElem.elementTypeProperties[k].propertyValue;
case "viz_dimension2":
dimension2=chartElem.elementTypeProperties[k].propertyValue;
break;
case "viz_measure1":
measure1=chartElem.elementTypeProperties[k].propertyValue;
break;
default:
break;
}
}
}
//get MetaData:
//alert(dimension1+"-"+dimension2+"-"+measure+"-"+ functionOfCategoryDim+"-"+functionOfDimension2+"-"+functionOfMeasureDim);
//get and transform Data:
var maxLenDimension1=0;
var maxMeasure=0;
var rowcount=myRs.length;
var rownr=1;
console.log("Zeilenanzahl " +rowcount);
myRs.forEach((row) => {
for (var col in row) {
console.log(col +"-"+row[col]);
if(col==dimension1)
dimension1Value=row[col];
if(col==dimension2)
dimension2Value=row[col];
if(col==measure1)
measure1Value=row[col];
}
data.push(new d3dataRow(rownr,dimension1Value,dimension2Value,measure1Value));
rownr++;
}
);
/*
console.log(rownr +"-" + dimension1Value +"-" +dimension2Value +"-" +measureDimValue);
selectionRs.push(new d3dataRow(rownr,dimension1Value,dimension2Value,measureDimValue));
//identify max String length to compute x axis size
if(dimension1Value.length >maxLenDimension1)
maxLenDimension1=dimension1Value.length;
//the same for values:
if(measureDimValue >maxMeasure)
maxMeasure=measureDimValue;
}
//TODO:Sorting and filtering
*/
return data;
}
function fillSelectionResult(selectionRsMetaData)
{
//OBSOLETE:
var selectionRs=[];
//get MetaData:
var dimension1,dimension2,measure,
@ -1437,6 +1593,48 @@ switch (chartType) @@ -1437,6 +1593,48 @@ switch (chartType)
return plotMark;
}
function renderChartElementWithD3(chartElem)
{
var mySvg= d3.select("#chartDiv").selectAll("svg");//.append("svg");
if(chartElem)
{
var chartType=chartElem.vizTypeUniquename;
var myDatasourceRs=rs[chartElem.datasource];
var data=filld3data(rs[chartElem.datasource],rsColumnMetaData[chartElem.datasource],chartElem);
console.log("Mark-option for "+chartType);
switch (chartType)
{
case "bar_x_d3":
makeBarX_d3(mySvg,data,chartElem);
break;
default:
alert("Unknown chart type");
break;
}
}
//return mySvg;
}
function renderChartElementWithD3V3(chartElem,targetDiv)
{
if(chartElem)
{
var chartType=chartElem.vizTypeUniquename;
var myDatasourceRs=rs[chartElem.datasource];
var data=filld3data(rs[chartElem.datasource],rsColumnMetaData[chartElem.datasource],chartElem);
console.log("Mark-option for "+chartType);
switch (chartType)
{
case "sankey":
makeSankey(targetDiv,data,rsColumnMetaData[chartElem.datasource],chartElem);
break;
default:
alert("Unknown chart type");
break;
}
}
//return mySvg;
}
function createChart(chartDivElem)
{
//OBSOLETE!
@ -1503,18 +1701,18 @@ switch (chartType) @@ -1503,18 +1701,18 @@ switch (chartType)
}
function makeBarX_alt(svg,data)
function makeBarX_d3(svg,data,chartElem)
{
var barHeight = 18;
var barLabelWidth = 500;
var barLabelPadding = 10;
var maxBarWidth = maxValue;
var fontSize=getCommonChartProperty("fontSize");
var chartWidth=getCommonChartProperty("chartWidth");
var maxValue=d3.max(data, d => d.value);
var maxLenName=d3.max(data, d => d.name.length);
//var barLabelWidth = 500;
//var barLabelPadding = 10;
//var maxBarWidth = maxValue;
var fontSize=12;//getCommonChartProperty("fontSize");
var chartWidth=800;//getCommonChartProperty("chartWidth");
var maxValue=d3.max(data, d => d.measure1);
var maxLenName=d3.max(data, d => d.dimension1.length);
var maxLenNamePx=maxLenName*fontSize;
var x = d3.scaleLinear().domain([0, d3.max(data, d => d.value)]).range([0, chartWidth]);
var x = d3.scaleLinear().domain([0, d3.max(data, d => d.measure1)]).range([0, chartWidth]);
var y = d3.scaleBand().domain(data.map(d => d.nr)).range([0, barHeight * data.length]);
const bar = svg.selectAll("g")
.data(data)
@ -1533,18 +1731,18 @@ function makeBarX_alt(svg,data) @@ -1533,18 +1731,18 @@ function makeBarX_alt(svg,data)
.transition()
.duration(750)
.delay(function(d, i) { return i * 10; })
.attr("width", d => x(d.value)) //x)
.attr("width", d => x(d.measure1)) //x)
.attr("height", y.bandwidth() - 1)
;
//value label:
bar.append("text")
.attr("fill", "white")
.attr("x", d => x(d.value)/2)
.attr("x", d => x(d.measure1)/2)
.attr("y", (y.bandwidth() - 1) / 2)
.attr("dy", "0.35em")
.attr("text-anchor","middle")
.text(d => d.value);
.text(d => d.measure1);
//label:
bar.append("text")
.attr("fill", "black")
@ -1552,7 +1750,8 @@ function makeBarX_alt(svg,data) @@ -1552,7 +1750,8 @@ function makeBarX_alt(svg,data)
.attr("y", (y.bandwidth() - 1) / 2)
.attr("dy", "0.35em")
.attr("text-anchor","end")
.text(d => d.name);
.text(d => d.dimension1);
//return bar;
}
function makeLine_alt(svg,data) {
@ -1911,6 +2110,20 @@ var options = { @@ -1911,6 +2110,20 @@ var options = {
function getChartPropertyValue(propArray,propName)
{
var propertyValue="";
for (var i=0;i<propArray.length;i++)
{
if(propArray[i].name==propName )
{
propertyValue=propArray[i].propertyValue;
}
}
return propertyValue;
}
function getCommonChartProperty(name)
{
var propertyValue="";
@ -1927,8 +2140,6 @@ function getCommonChartProperty(name) @@ -1927,8 +2140,6 @@ function getCommonChartProperty(name)
}
return propertyValue;
}
function showSrcCode(renderer)
{
var myChartDiv= document.getElementById("chartDiv2");

25
superx/xml/viz_html_chart.xsl

@ -17,7 +17,10 @@ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:HtmlUtils="de.superx.util @@ -17,7 +17,10 @@ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:HtmlUtils="de.superx.util
<!-- wichtig für DOJO!-->
<xsl:output method="xml" media-type="text/html" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="DTD/xhtml1-strict.dtd" cdata-section-elements="script style" indent="yes" encoding="UTF-8"/>
<xsl:variable name="defaultRenderer" select="'plot'" />
<xsl:variable name="availableRendererPlot" select="'true'" />
<xsl:variable name="availableRendererD3" select="'true'" />
<xsl:variable name="availableRendererD3V3" select="'false'" />
<xsl:template match="/">
<xsl:call-template name="table"/>
</xsl:template>
@ -119,12 +122,15 @@ padding-bottom:10px; @@ -119,12 +122,15 @@ padding-bottom:10px;
<!-- end css -->
<!-- start Javascript-->
<xsl:template name="tableJavascript_viz">
<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/plot.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']">
<script language="Javascript" type="text/javascript" src="{@srcpath}" />
</xsl:for-each>
</xsl:template>
<xsl:template name="tableJavascript_viz">
<xsl:call-template name="importVizJavascriptLibs" />
<script><xsl:text><![CDATA[
@ -1798,9 +1804,16 @@ rs[</xsl:text><xsl:value-of select="$tableId"/><xsl:text>].push(new dataRow_</xs @@ -1798,9 +1804,16 @@ rs[</xsl:text><xsl:value-of select="$tableId"/><xsl:text>].push(new dataRow_</xs
<div class="field is-active">
<p class="control-new">
<div class="select is-small is-fullwidth">
<select class="maskinputPflicht" id="fldVizRenderer" NAME="fldVizRenderer" tabindex="1" onChange="" >
<option class="maskinput" value="plot" selected="selected">Observable Plot</option>
<select class="maskinputPflicht" id="fldVizRenderer" NAME="fldVizRenderer" tabindex="1" onChange="resetChartPropertiesForm();" >
<xsl:if test="$availableRendererPlot='true'">
<option class="maskinput" value="plot" selected="selected">Observable Plot</option>
</xsl:if>
<xsl:if test="$availableRendererD3='true'">
<option class="maskinput" value="d3js" >D3JS</option>
</xsl:if>
<xsl:if test="$availableRendererD3V3='true'">
<option class="maskinput" value="d3jsv3" >D3JS (Version 3)</option>
</xsl:if>
</select>
</div>
@ -1871,13 +1884,13 @@ rs[</xsl:text><xsl:value-of select="$tableId"/><xsl:text>].push(new dataRow_</xs @@ -1871,13 +1884,13 @@ rs[</xsl:text><xsl:value-of select="$tableId"/><xsl:text>].push(new dataRow_</xs
<p class="bd-notification is-fojeisj">Vorschau</p>
<div id="chartCanvas">
<div id="chartDiv">
<svg viewBox="0 0 650 450">
<svg>
<rect x="0" y="0" width="650" height="450" fill="#cccccc"></rect>
</svg></div>
</div>
</div>
</div><!--Ende Eigenschaften + Vorschau-->
</div><!--Ende Eigenschaften + Vorschau viewBox="0 0 650 450"-->
</form>
</div>

34
superx/xml/viz_html_chart_sankey.xsl

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:HtmlUtils="de.superx.util.HtmlUtils">
<xsl:import href="xsl_functions.xsl" />
<xsl:import href="resultset_html.xsl" />
<xsl:import href="interLinks_html.xsl" />
<xsl:import href="pageComponents_html.xsl" />
<xsl:import href="pageComponents_html_final.xsl" />
<xsl:import href="viz_html_chart.xsl" />
<xsl:import href="menue_html_dojo.xsl" />
<!--In diesem Stylesheet können Sie individuelle templates unterbringen,
die in ihrer Präzedenz das normale Stylesheet
pageComponents_html.xsl überragt. -->
<xsl:import href="pageComponents_html_final.xsl" />
<xsl:decimal-format name="German" grouping-separator="." NaN="" zero-digit ="0" decimal-separator="," />
<!-- wichtig für DOJO!-->
<xsl:output method="xml" media-type="text/html" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="DTD/xhtml1-strict.dtd" cdata-section-elements="script style" indent="yes" encoding="UTF-8"/>
<xsl:variable name="defaultRenderer" select="'d3jsv3'" />
<xsl:variable name="availableRendererPlot" select="'false'" />
<xsl:variable name="availableRendererD3" select="'false'" />
<xsl:variable name="availableRendererD3V3" select="'true'" />
<xsl:template match="/">
<xsl:call-template name="table"/>
</xsl:template>
<xsl:template name="importVizJavascriptLibs">
<script language="Javascript" type="text/javascript" src="../xml/js/viz/d3.v3.min.js" />
<script language="Javascript" type="text/javascript" src="../xml/js/viz/viz_functions.js" />
<script language="Javascript" type="text/javascript" src="../xml/js/viz/sankey_v3.js" />
</xsl:template>
</xsl:stylesheet>
Loading…
Cancel
Save