Visualisierungsmodul für SuperX http://www.superx-projekt.de/doku/viz_modul/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

613 lines
16 KiB

/* d3 Code */
function d3dataRow(nr,name,value )
{
this.nr=nr;
this.name=name;
this.value=value;
}
function chartPropertyValue(nr,name,value,isDefault )
{
this.nr=nr;
this.name=name;
this.value=value;
this.isDefault=isDefault;
}
function dimFunction(nr,name,value,isDefault )
{
this.nr=nr;
this.name=name;
this.value=value;
this.isDefault=isDefault;
}
3 years ago
function chartProperty(name,caption,isDynamic,isMeasure,isMandatory,staticValues,defaultValue,optionalFunction)
{
this.name=name;
this.caption=caption;
this.isDynamic=isDynamic;
this.isMeasure=isMeasure;
this.staticValues=staticValues;
3 years ago
this.isMandatory=isMandatory;
this.defaultValue=defaultValue;
this.optionalFunction=optionalFunction;
this.getValueResultset = function () {
var valueOptions=[];
var optionCounter=0;
if(isDynamic)
{
for(var j=0;j < rsMetaData.length;j++)
{
var isDefault=false;
if(rsMetaData[j].colcaption.trim() !="" &&
(isMeasure==false || rsMetaData[j].coltype == 4 || rsMetaData[j].coltype == 3)
)
{
if(rsMetaData[j].colcaption==defaultValue)
isDefault=true;
var o=new chartPropertyValue(rsMetaData[j].nr,rsMetaData[j].colcaption,rsMetaData[j].nr,isDefault);
valueOptions[optionCounter]=o;
optionCounter++;
}
}
}
else
{
var staticValuesArray = staticValues.split(/\|/);
for(var k=0;k < staticValuesArray.length;k++)
{
var isDefault=false;
if(rsMetaData[j].colcaption==defaultValue)
isDefault=true;
var o=new chartPropertyValue(k,staticValuesArray[k],staticValuesArray[k],isDefault);
valueOptions[k]=o;
}
}
return valueOptions;
}
}
function prepareChartProperties(chartType)
{
var dimFunctions=[];
var myFunction= new dimFunction(0,"Wort 1 ans Ende","switchWord1and2ff",false);
dimFunctions[0]=myFunction;
var chartProperties=[];
switch (chartType) {
case "bar_x":
chartProperties=prepareBarXForm();
break;
3 years ago
case "bar_y":
chartProperties=prepareBarYForm();
break;
case "line":
chartProperties=prepareLineForm();
break;
default:
return false;
break;
}
renderForm("chartProperties",chartProperties,commonChartProperties,dimFunctions);
return true;
}
function prepareBarXForm()
{
var chartProperties=[];
var propertyCounter=0;
3 years ago
var myProp= new chartProperty("viz_category_dim","Kategorie-Dimension",true,false,true,null,null,true);
chartProperties[0]=myProp;
3 years ago
var myProp= new chartProperty("viz_measure_dim","Maß",true,true,false,true,null,true);
chartProperties[1]=myProp;
return chartProperties;
}
3 years ago
function prepareBarYForm()
{
var chartProperties=[];
var propertyCounter=0;
3 years ago
var myProp= new chartProperty("viz_category_dim","Kategorie-Dimension",true,false,true,null,null,true);
chartProperties[0]=myProp;
3 years ago
var myProp= new chartProperty("viz_series_dim","Serien-Dimension",true,false,false,null,null,true);
chartProperties[1]=myProp;
3 years ago
var myProp= new chartProperty("viz_measure_dim","Maß",true,true,true,null,null,true);
chartProperties[2]=myProp;
return chartProperties;
}
function prepareLineForm()
{
var chartProperties=[];
var propertyCounter=0;
3 years ago
var myProp= new chartProperty("viz_category_dim","X-Achse",true,false,true,null,null,true);
chartProperties[0]=myProp;
3 years ago
var myProp= new chartProperty("viz_measure_dim","Y-Achse",true,true,true,null,null,true);
chartProperties[1]=myProp;
return chartProperties;
}
function renderForm(formDiv,chartProperties,myCommonChartProperties,dimFunctions)
{
//first empty form:
var myForm=document.getElementById(formDiv);
while (myForm.firstChild) {
myForm.removeChild(myForm.firstChild);
}
//now fill it:
const tabElem = document.createElement("table");
myForm.appendChild(tabElem);
for(var k=0;k < chartProperties.length;k++)
{
const rowElem = document.createElement("tr");
const tdCap = document.createElement("td");
const textnode = document.createTextNode(chartProperties[k].caption);
tdCap.appendChild(textnode);
const tdSelElem = document.createElement("td");
const selElem = document.createElement("select");
selElem.name=chartProperties[k].name;
selElem.id=chartProperties[k].name;
3 years ago
fillSelectOptions(selElem,chartProperties[k].getValueResultset(),chartProperties[k].isMandatory);
tdSelElem.appendChild(selElem);
if(chartProperties[k].optionalFunction)
{
const fnElemLabel = document.createTextNode(" opt. Fkt.: ");
const fnSelElem = document.createElement("select");
fnSelElem.name=chartProperties[k].name+"_fn";
fnSelElem.id=chartProperties[k].name+"_fn";
fillSelectOptions(fnSelElem,dimFunctions,false);
tdSelElem.appendChild(fnElemLabel);
tdSelElem.appendChild(fnSelElem);
}
rowElem.appendChild(tdCap);
rowElem.appendChild(tdSelElem);
//here values, and then:
tabElem.appendChild( rowElem);
}
/*
const rowElem = document.createElement("tr");
const tdCap = document.createElement("td");
const textnode = document.createTextNode("Breite");
tdCap.appendChild(textnode);
const tdInpElem = document.createElement("td");
const inpElem = document.createElement("input");
inpElem.id="viz_width";
inpElem.name="viz_width";
inpElem.type="text";
inpElem.value="800";
tdInpElem.appendChild(inpElem);
rowElem.appendChild(tdCap);
rowElem.appendChild(tdInpElem);
tabElem.appendChild(rowElem);
*/
myForm.appendChild(tabElem);
//TODO: myCommonChartProperties auf separatem TAB
}
function fillSelectOptions(myCombo,myValues,isMandatory)
{
var optionCounter=0;
var selectedOption=null;
while (myCombo.firstChild) {
myCombo.removeChild(myCombo.firstChild);
}
var optionCounter=0;
if(!isMandatory)
{
//add an empty option:
var o=new Option("","");
myCombo.options[optionCounter]=o;
optionCounter++;
}
for(var j=0;j < myValues.length;j++)
{
if(myValues[j].isDefault)
selectedOption=optionCounter;
var o=new Option(myValues[j].name,myValues[j].value,null,null);
myCombo.options[optionCounter]=o;
optionCounter++;
}
if(selectedOption!=null)
myCombo.selectedIndex=selectedOption;
}
function prepareData()
{
var data=[];
var rowcount=rs.length;
var colnrOfCategorydimName=document.getElementById("viz_category_dim").value;
var colnrOfMeasure=document.getElementById("viz_measure_dim").value;
var functionOfCategoryDim=document.getElementById("viz_category_dim_fn").value;
var functionOfMeasureDim=document.getElementById("viz_measure_dim_fn").value;
var maxLenName=0;
var maxValue=0;
for(j=1;j<rowcount;j++)
{
console.log(rs.length+"-"+j+"-"+colnrOfCategorydimName);
if(rs[j][colnrOfCategorydimName]) //only if Name is not empty:
{
var categoryDimValue=rs[j][colnrOfCategorydimName];
var measureDimValue=rs[j][colnrOfMeasure];
if(functionOfCategoryDim !="")
categoryDimValue=applyFunction(categoryDimValue,functionOfCategoryDim);
if(functionOfMeasureDim !="")
measureDimValue=applyFunction(measureDimValue,functionOfMeasureDim);
data.push(new d3dataRow(j,categoryDimValue,measureDimValue));
//identify max String length to compute x axis size
if(categoryDimValue.length >maxLenName)
maxLenName=categoryDimValue.length;
//the same for values:
if(measureDimValue >maxValue)
maxValue=measureDimValue;
}
}
return data;
}
function showDataTable()
{
tableDiv=document.getElementById("tableDiv");
tableDiv.innerHTML=""; //reset table
var rowcount=rs.length;
const tabElem = document.createElement("table");
tabElem.border="1";
tabElem.width="100%";
const rowElem = document.createElement("tr");
for(var col=0;col < rsMetaData.length;col++)
{
const thCap = document.createElement("th");
const textnode = document.createTextNode(rsMetaData[col].colcaption);
thCap.appendChild(textnode);
rowElem.appendChild(thCap);
}
tabElem.appendChild(rowElem);
for(row=1;row<rowcount;row++)
{
if(rs[row])
{
const rowElem = document.createElement("tr");
for(var col=1;col < rs[row].length;col++)
{
const tdCap = document.createElement("td");
if(rs[row][col])
{
const textnode = document.createTextNode(rs[row][col]);
tdCap.appendChild(textnode);
}
rowElem.appendChild(tdCap);
}
tabElem.appendChild(rowElem);
}
}
tableDiv.appendChild(tabElem);
}
function createChart()
{
chartType=document.getElementById("viz_chart_type").value;
/*
if(document.getElementById("viz_category_dim").value=="" ||
document.getElementById("viz_measure_dim").value=="" )
{
alert("Bitte wählen Sie eine Kategorie und ein Maß");
return false;
}
*/
var data=[];
data=prepareData();
var valueLabelWidth = getCommonChartProperty("valueLabelWidth");
var fontFamily=getCommonChartProperty("fontFamily");
var gridLabelHeight = getCommonChartProperty("gridLabelHeight");
var gridChartOffset = getCommonChartProperty("gridChartOffset");
var chartWidth=getCommonChartProperty("chartWidth");
var fontSize=getCommonChartProperty("fontSize");
document.getElementById("chartDiv").innerHTML=""; //reset canvas
var svg = d3.select("#chartDiv").append("svg")
.attr("width", chartWidth) //maxBarWidth + barLabelWidth + valueLabelWidth)
//.attr("height", y.range()[1])
.attr("font-family", fontFamily)
.attr("font-size", fontSize)
.attr("text-anchor", "start")
.attr("id", "chartSVG")
;
switch (chartType)
{
case "bar_x":
makeBarX(svg,data);
break;
3 years ago
case "bar_y":
makeBarY(svg,data);
break;
case "line":
makeLine(svg,data);
break;
default:
alert("Please select a chart type");
break;
}
}
function makeBarX(svg,data)
{
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 maxLenNamePx=maxLenName*fontSize;
var x = d3.scaleLinear().domain([0, d3.max(data, d => d.value)]).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)
.join("g")
.attr("transform", d => `translate(${maxLenNamePx},${y(d.nr)})`)
;
bar.append("rect")
.attr("fill", "steelblue")
.on("mouseover",function(){
d3.select(this).attr("fill", "red");
})
.on("mouseout",function(){
d3.select(this).attr("fill", "steelblue");
})
.transition()
.duration(750)
.delay(function(d, i) { return i * 10; })
.attr("width", d => x(d.value)) //x)
.attr("height", y.bandwidth() - 1)
;
//value label:
bar.append("text")
.attr("fill", "white")
.attr("x", d => x(d.value)/2)
.attr("y", (y.bandwidth() - 1) / 2)
.attr("dy", "0.35em")
.attr("text-anchor","middle")
.text(d => d.value);
//label:
bar.append("text")
.attr("fill", "black")
.attr("x", 0)
.attr("y", (y.bandwidth() - 1) / 2)
.attr("dy", "0.35em")
.attr("text-anchor","end")
.text(d => d.name);
}
function makeLine(svg,data) {
var xLabel=rsMetaData[document.getElementById("viz_category_dim").value-1].colcaption;
var yLabel=rsMetaData[document.getElementById("viz_measure_dim").value-1].colcaption;
var fontSize=getCommonChartProperty("fontSize");
var maxLenName=d3.max(data, d => d.name.length);
var maxLenNamePx=maxLenName*fontSize/1.5;
var marginLeftPx=xLabel.length*fontSize;
var options = {
marginBottom:maxLenNamePx,
marginLeft:marginLeftPx,
x: {
tickRotate: -45,
ticks: 5,
tickSize: 5,
line: true,
tickPadding: 10,
labelAnchor: "left",
labelOffset: 0,
nice: true,
label: xLabel,
type:"point"
},
// set y axis options
y: {
grid:true,
label: yLabel
},
sort: "nr",
// define the marks we will use, dots and a line
marks: [
Plot.line(data, {x: "name", y: "value",curve:"linear"}),
Plot.dot(data, {x: "name", y: "value" })
]
};
document.getElementById("chartDiv").appendChild(Plot.plot(options));
}
3 years ago
function makeBarY(svg,data) {
var xLabel=rsMetaData[document.getElementById("viz_category_dim").value-1].colcaption;
var yLabel=rsMetaData[document.getElementById("viz_measure_dim").value-1].colcaption;
var fontSize=getCommonChartProperty("fontSize");
var maxLenName=d3.max(data, d => d.name.length);
var maxLenNamePx=maxLenName*fontSize/1.5;
var marginLeftPx=xLabel.length*fontSize;
var options = {
marginBottom:maxLenNamePx,
marginLeft:marginLeftPx,
x: {
tickRotate: -45
},
// set y axis options
y: {
grid:true,
label: yLabel
},
3 years ago
marks: [
3 years ago
Plot.barY(data,
Plot.groupX(
{y: "sum"},
{
x: "name",
y: "value"
3 years ago
}
)
)
]
}
document.getElementById("chartDiv").appendChild(Plot.plot(options));
}
function getCommonChartProperty(name)
{
var propertyValue="";
for (var i=0;i<commonChartProperties.length;i++)
{
if(commonChartProperties[i].name==name)
propertyValue=commonChartProperties[i].defaultValue; //TODO aus formular übersteuern
}
return propertyValue;
}
function showSrcCode()
{
var myChartDiv= document.getElementById("chartDiv");
var numberOfChildNodes=myChartDiv.childNodes.length;
var svg_xml ="";
for (var i=0;i<numberOfChildNodes;i++)
{
var myNode=myChartDiv.childNodes[i];
if(myNode.nodeName=="svg")
{
var mySvg=myNode; //document.getElementById("chartSVG");
// Extract the data as SVG text string
svg_xml = (new XMLSerializer).serializeToString(mySvg);
}
}
//alert(svg_xml);
document.getElementById("chartSrc").innerHTML=svg_xml;
document.getElementById("chartSrcFields").style.visibility="visible";
/*
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(ergtabelle);
selection.removeAllRanges();
selection.addRange(range);
document.execCommand('copy');
selection.removeAllRanges();
alert("Angezeigte Tabelle wurde in die Zwischenablage kopiert.");
*/
}
function copySrcCode(mydiv)
{
var ergtabelle=document.getElementById(mydiv);
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(ergtabelle);
selection.removeAllRanges();
selection.addRange(range);
document.execCommand('copy');
selection.removeAllRanges();
}
function makeHisto() {
d3.csv( "/superx/xml/js/d3/dense.csv" ).then( function( data ) {
var histo = d3.histogram().value( d=>+d.A )( data );
var height=400;
var scX = d3.scaleBand().padding( 0.2 ).round( true )
.range( [15, 515] ).domain( histo );
var scY = d3.scaleLinear().range( [height, 0] )
.domain( [0, d3.max( histo, d=>d.length ) ] ).nice();
var g = d3.select("#chartDiv").append("svg")
.append( "g" ).attr( "transform", "translate( 40,50 )" )
g.selectAll( "rect" ).data( histo ).enter()
.append( "rect" ).attr( "width", scX.bandwidth() )
.attr( "x", scX ).attr( "y", d=>scY(d.length) )
.attr( "height", d => height-scY(d.length) )
.attr( "fill", "red" ).attr( "fill-opacity", 0.2 )
.attr( "stroke", "red" ).attr( "stroke-width", 2 )
g.selectAll( "text" ).data( histo ).enter().append( "text" )
.attr( "text-anchor", "middle" )
.attr( "font-family", "sans-serif" )
.attr( "font-size", 14 )
.attr( "x", d => scX(d)+0.5*scX.bandwidth() )
.attr( "y", 225 )
.text( d=>(d.x0+d.x1)/2 );
g.append( "g" ).call( d3.axisLeft(scY) );
} );
}
function applyFunction(theValue,theFunction)
{
switch (theFunction) {
case "switchWord1and2ff":
var ret=switchWord1and2ff(theValue);
break;
default:
var ret=theValue;
break;
}
return ret;
}
function switchWord1and2ff(theString)
{
//erzeugt z.B. aus "WiSe 2020/2021" den Wert "2020/2021", zum Sortieren
var theWords = theString.split(/ /);
var word1=theWords[0];
var word2="";
var ret="";
if(theWords.length >1)
{
for(var k=1;k < theWords.length;k++)
{
word2+= theWords[k];
}
ret +=word2;
}
ret+=" "+ word1;
return ret.trim();
}