'use strict';
function fixOverlaySize() {
var tmp = document.getElementsByClassName("centerhv");
for (var i = 0; i < tmp.length; ++i) {
tmp[i].style.left = ($(window).width() - $(tmp[i]).outerWidth()) / 2;
tmp[i].style.top = ($(window).height() - 32 - $(tmp[i]).outerHeight()) / 2 + 32;
}
}
var namedContainers = [];
// Performance measurement functions
// var tictime;
/*
* if (!window.performance || !performance.now) { window.performance = { now:
* Date.now } }
*/
function tic() {/* tictime = performance.now() */
}
function toc(msg) {
// var dt = performance.now()-tictime;
// console.log((msg||'toc') + ": " + dt + "ms");
}
function replaceAll(str, s, r) {
return str.split(s).join(r);
}
function isValidDate(d) {
if (Object.prototype.toString.call(d) !== "[object Date]")
return false;
return !isNaN(d.getTime());
}
function getCheckbox(labelname, containerControl) {
var div = document.createElement('div');
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.setAttribute('style', 'position:relative; top:2px;');
checkbox.setAttribute('id', labelname);
var label = document.createElement('label');
label.setAttribute('for', labelname);
label.innerHTML = ' ' + labelname;
div.appendChild(checkbox);
div.appendChild(label);
containerControl.appendChild(div);
return checkbox;
}
function display(json, page, phantomJS) {
tic();
var container = document.createElement('div');
container.id = json.name;
container.className = "overlay";
var style;
if (phantomJS) {
style = "width: 100%; height: 100%; margin: 0px;";
} else {
style = "position: absolute; width:" + (json.type.I.x2 - json.type.I.x1 + 0.001) * 100 + "%; height:" + (json.type.I.y1 - json.type.I.y2 + 0.001) * 100 + "%; left:" + json.type.I.x1 * 100 + "%; bottom:" + (json.type.I.y2 - 0.001) * 100 + "%;";
}
if (typeof font_store === "undefined" || typeof font_store[json.name] === "undefined") {
style += "font-size: " + (zoomFactor * 12.0) + "pt; font-family: sans-serif;"
} else {
style += "font-size: " + (zoomFactor * 12.0) + "pt; font-family: " + font_store[json.name] + ", sans-serif;"
}
page.appendChild(container);
var containerOver = document.getElementById(json.name + "Big");
// if (containerOver != null) {
// containerOver.update();
// } TODO: reenable if textsize of overlays can be changed
var styleBig = 'position:fixed; z-index:-1; border:1px solid black; padding:10px; background:#DDDDDD; width:95%; height:87%; opacity:0; visibility:hidden; -webkit-transition:opacity 500ms ease-out; -moz-transition:opacity 500ms ease-out; -o-transition:opacity 500ms ease-out; transition:opacity 500ms ease-out; overflow:auto; overflow-y:scroll; white-space: nowrap;';
if (typeof font_store === "undefined" || typeof font_store[json.name] === "undefined") {
styleBig += "font-size: " + (rawZoomFactor * 12.0) + "pt; font-family: sans-serif;"
} else {
styleBig += "font-size: " + (rawZoomFactor * 12.0) + "pt; font-family: " + font_store[json.name] + ", sans-serif;"
}
switch (json.type.C) {
case "pdbf.json.MultiplotChart":
if (!phantomJS) {
var fullscreen = getFullscreenDiv();
container.appendChild(fullscreen);
fullscreen.addEventListener("click", function() {
if (containerOver == null) {
containerOver = document.createElement('div');
containerOver.setAttribute('style', styleBig);
containerOver.id = json.name + "Big";
containerOver.className = "centerhv";
buildContainerChartBig(json, containerOver, true);
}
containerOver.style.visibility = 'visible';
containerOver.style['z-index'] = 9;
containerOver.style.opacity = 1;
$("svg").css('display', 'none');
$("svg").css('height');
$("svg").css('display', 'initial');// HACK for redraw of
// SVG
});
}
container.setAttribute('style', style);
if (json.type.I.customImage == null) {
buildContainerMultiplotChart(container, json, zoomFactor, style, containerOver);
if (json.type.I.name != null && json.type.I.name != "") {
namedContainers[json.type.I.name] = {
type : "MultiplotChart",
elem : undefined
}; // TODO:
}
}
break;
case "pdbf.json.Chart":
if (!phantomJS) {
var fullscreen = getFullscreenDiv();
container.appendChild(fullscreen);
fullscreen.addEventListener("click", function() {
if (containerOver == null) {
containerOver = document.createElement('div');
containerOver.setAttribute('style', styleBig);
containerOver.id = json.name + "Big";
containerOver.className = "centerhv";
buildContainerChartBig(json, containerOver, true);
}
containerOver.style.visibility = 'visible';
containerOver.style['z-index'] = 9;
containerOver.style.opacity = 1;
$("svg").css('display', 'none');
$("svg").css('height');
$("svg").css('display', 'initial');// HACK for redraw of
// SVG
});
}
container.setAttribute('style', style);
if (json.type.I.customImage == null) {
buildContainerChart(container, json, zoomFactor, style, containerOver);
if (json.type.I.name != null && json.type.I.name != "") {
namedContainers[json.type.I.name] = {
type : "Chart",
elem : json.chartInPage,
opt : json.options
};
}
}
break;
case "pdbf.json.DataTable":
if (phantomJS) {
var text = buildDataTable(container, json, zoomFactor, style, containerOver);
if (text != undefined) {
json.text = text;
}
}
if (!phantomJS) {
container.addEventListener("click", function() {
if (containerOver == null) {
containerOver = document.createElement('div');
containerOver.setAttribute('style', styleBig);
containerOver.id = json.name + "Big";
containerOver.className = "centerhv";
buildContainerTableBig(json, containerOver);
}
containerOver.style.visibility = 'visible';
containerOver.style['z-index'] = 9;
containerOver.style.opacity = 1;
});
}
style += 'cursor: pointer;';
container.setAttribute('style', style);
break;
case "pdbf.json.DataText":
if (phantomJS) {
var text = buildDataText(container, json, zoomFactor, style, containerOver);
if (text != undefined) {
json.text = text;
}
}
if (json.type.I.linkTo != null && json.type.I.linkTo != "") {
container.addEventListener("mouseover", function() {
var o = namedContainers[json.type.I.linkTo];
if (o == undefined) {
alert("Error! There is no element with name \"" + json.type.I.linkTo + "\"");
}
switch (o.type) {
case "Chart":
o.elem.xgrids.add([ {
value : json.type.I.linkSelector,
text : json.type.I.linkLabel
} ]);
break;
case "MultiplotChart":
case "Pivot":
default:
alert("Error! linkTo currently only supports chart elements.")
break;
}
});
container.addEventListener("mouseout", function() {
var o = namedContainers[json.type.I.linkTo];
if (o == undefined) {
alert("Error! There is no element with name \"" + json.type.I.linkTo + "\"");
}
switch (o.type) {
case "Chart":
o.elem.xgrids.remove({
value : json.type.I.linkSelector
});
break;
case "MultiplotChart":
case "Pivot":
default:
alert("Error! linkTo currently only supports chart elements.")
break;
}
});
}
// Fallthrough
case "pdbf.json.Text":
if (!phantomJS) {
container.addEventListener("click", function() {
if (containerOver == null) {
containerOver = document.createElement('div');
containerOver.setAttribute('style', styleBig);
containerOver.id = json.name + "Big";
containerOver.className = "centerhv";
buildContainerTableBig(json, containerOver);
}
containerOver.style.visibility = 'visible';
containerOver.style['z-index'] = 9;
containerOver.style.opacity = 1;
});
}
style += 'cursor: pointer;';
container.setAttribute('style', style);
break;
case "pdbf.json.Pivot":
if (!phantomJS) {
var fullscreen = getFullscreenDiv();
container.appendChild(fullscreen);
fullscreen.addEventListener("click", function() {
if (containerOver == null) {
containerOver = document.createElement('div');
containerOver.setAttribute('style', styleBig);
containerOver.id = json.name + "Big";
containerOver.className = "centerhv";
buildContainerPivotBig(json, containerOver, true);
}
containerOver.style.visibility = 'visible';
containerOver.style['z-index'] = 9;
containerOver.style.opacity = 1;
});
}
container.setAttribute('style', style);
if (json.type.I.customImage == null) {
buildContainerPivot(container, json, zoomFactor, style, containerOver);
if (json.type.I.name != null && json.type.I.name != "") {
namedContainers[json.type.I.name] = {
type : "Pivot",
elem : undefined
}; // TODO:
}
// Check if Pivot table fits into the div. If not then decrease
// the font-size until it fits or until we reach a negative zoomFactor
var container = $(container).children().last().children();
var cur = 0.1;
container.css('font-size', cur + "pt");
var width = container.width();
var height = container.height();
while ((container.width() == width && container.height() == height) && cur <= zoomFactor * 12.0) {
cur = cur + 0.1;
$(container).css('font-size', cur + "pt");
}
cur = cur - 0.1;
$(container).css('font-size', cur + "pt");
}
break;
default:
alert("Unknown type: " + json.type.C);
break;
}
toc("Display time for " + json.name);
}
function buildContainerChartBig(json, containerOver, initial) {
containerOver.updateData = function() {
json.jsonBig.type.I.query = ref.editor.getValue();
containerOver.update();
};
containerOver.update = function() {
json.jsonBig.type.I.logScale = logScale.checked;
json.jsonBig.type.I.includeZero = includeZero.checked;
if (json.type.I.chartType == 'Line' || json.type.I.chartType == 'line') {
json.jsonBig.type.I.drawPoints = drawPoints.checked;
json.jsonBig.type.I.fillGraph = fillGraph.checked;
}
json.jsonBig.type.I.showRangeSelector = showRangeSelector.checked;
json.chartdataBig = getChartData(json.jsonBig);
json.resultBig = json.chartdataBig.res;
if (json.chartdataBig.error != undefined) {
error.innerHTML = 'Query status: Error! ' + json.chartdataBig.error;
containerOptions.style.visibility = 'hidden';
containerChart.style.visibility = 'hidden';
return;
} else {
error.innerHTML = 'Query status: OK';
containerOptions.style.visibility = 'visible';
containerChart.style.visibility = 'visible';
}
var optionsBig = getChartOptions(json.jsonBig, rawZoomFactor, json.chartdataBig.values, containerContent);
if (logScale.checked) {
includeZero.disabled = true;
} else {
includeZero.disabled = false;
}
if (includeZero.checked) {
logScale.disabled = true;
} else {
logScale.disabled = false;
}
json.chart = c3.generate(optionsBig);
};
var viewerContainer = document.getElementById("viewerContainer");
var tip = "Tip: Scroll to zoom the graph. Click and drag to pan the graph.
";
json.jsonBig = jQuery.extend(true, {}, json);
var ref = prepopulateContainerOver(containerOver, viewerContainer, tip, [ json ], containerOver.updateData, 'graph', true);
var containerContent = ref.containerContent;
var containerChart = ref.containerChart;
var containerOptions = ref.options;
var error = ref.error;
var logScale = getCheckbox('LogScale (Y-Axis)', containerOptions);
logScale.addEventListener('change', containerOver.update);
logScale.checked = json.jsonBig.type.I.logScale;
json.jsonBig.type.I.showRangeSelector = true;
var includeZero = getCheckbox('IncludeZero', containerOptions);
includeZero.addEventListener('change', containerOver.update);
includeZero.checked = json.jsonBig.type.I.includeZero;
if (json.jsonBig.type.I.chartType == 'Line' || json.jsonBig.type.I.chartType == 'line') {
var fillGraph = getCheckbox('FillGraph', containerOptions);
fillGraph.addEventListener('change', containerOver.update);
fillGraph.checked = json.jsonBig.type.I.fillGraph;
var drawPoints = getCheckbox('DrawPoints', containerOptions);
drawPoints.addEventListener('change', containerOver.update);
drawPoints.checked = json.jsonBig.type.I.drawPoints;
}
var showRangeSelector = getCheckbox('ShowRangeSelector', containerOptions);
showRangeSelector.addEventListener('change', containerOver.update);
showRangeSelector.checked = json.jsonBig.type.I.showRangeSelector;
containerOver.update();
}
function buildContainerChart(container, json, zoomFactor, style, containerOver) {
var chart = document.createElement('div');
chart.setAttribute('style', 'width:100%; height:100%;');
container.appendChild(chart);
var chartdata;
if (json.result == undefined) {
chartdata = getChartData(json);
if (chartdata.error != undefined) {
alert(chartdata.error + '\nWhere: ' + json.name + '\nQuery was: ' + json.type.I.query);
return;
}
chartdata = chartdata.values;
json.result = chartdata;
} else {
chartdata = json.result;
}
style = "background: white;" + style;
container.setAttribute('style', style);
var options = getChartOptions(json, zoomFactor, chartdata, chart);
json.options = options;
json.chartInPage = c3.generate(options);
}
function buildDataText(container, json, zoomFactor, style, containerOver) {
var results;
try {
results = alasqlQuery(json.type.I.query);
} catch (e) {
alert(e.message);
return;
}
var error;
if (results.length == 0) {
alert("Query \"" + json.type.I.query + "\" returns empty result!");
return;
}
if (results[0] instanceof Array) {
alert("Query \"" + json.type.I.query + "\" contains multiple statements!");
return;
}
var c = 0;
for ( var key in results[0]) {
c++;
}
if (c == 0) {
alert("Query \"" + json.type.I.query + "\" returns no columns!");
return;
}
var tmp = "";
for ( var r in results) {
if (c > 1) {
tmp += "(";
}
var trunc = false;
for ( var key in results[r]) {
tmp += results[r][key] + ", ";
trunc = true;
}
if (trunc) {
tmp = tmp.substring(0, tmp.length - 2);
}
if (c > 1) {
tmp += "), ";
}
}
if (c > 1) {
tmp = tmp.substring(0, tmp.length - 2);
}
return tmp;
}
function buildDataTable(container, json, zoomFactor, style, containerOver) {
var results;
try {
results = alasqlQuery(json.type.I.query);
} catch (e) {
alert(e.message);
return;
}
var error;
if (results.length == 0) {
alert("Query \"" + json.type.I.query + "\" returns empty result!");
return;
}
if (results[0] instanceof Array) {
alert("Query \"" + json.type.I.query + "\" contains multiple statements!");
return;
}
var vmode = json.type.I.verticalLines.trim();
var hmodeh = json.type.I.horizontalLinesHeader.trim();
var hmode = json.type.I.horizontalLinesBody.trim();
var count = 0;
for ( var key in results[0]) {
++count;
}
if (count === 0) {
alert("Query \"" + json.type.I.query + "\" returns no columns!");
return;
}
// vertical lines
var c = 0;
var tmp = "\\begin{tabular}[t]{";
if (vmode === "a" || vmode === "o" || vmode === "i" || vmode === "n") {
for ( var key in results[0]) {
if (vmode === "n") {
tmp += "c";
} else if (c === 0) {
if (vmode === "a" || vmode === "o") {
tmp += "|c";
} else {
tmp += "c";
}
} else {
if (vmode === "a" || vmode === "i") {
tmp += "|c";
} else {
tmp += "c";
}
}
++c;
}
if (vmode === "a" || vmode === "o") {
tmp += "|}";
} else {
tmp += "}";
}
} else {
tmp += vmode + "}";
}
// header
if (hmodeh === "a" || hmodeh === "o" || hmodeh === "i" || hmodeh === "n") {
if (hmodeh === "a" || hmodeh === "o") {
tmp += "\\firsthline ";
}
} else {
var pattern = hmodeh.split(" ");
if (pattern.length != 2) {
alert("Format string is too short! Must contain exactly 2 format specifications. Format string was: " + hmodeh);
return;
}
var first = pattern[0].split('');
var firsth = true;
for (var i = 0; i < first.length; ++i) {
switch (first[i]) {
case 'h':
if (firsth) {
tmp += "\\firsthline";
firsth = false;
} else {
tmp += "\\hline"
}
break;
case 'b':
break;
default:
alert("Unknown format character found! Format string was: " + hmodeh);
return;
}
}
tmp += " ";
}
for ( var key in results[0]) {
tmp += "\\textbf{" + key + "}&";
}
tmp = tmp.substring(0, tmp.length - 1) + "\\\\";
if (hmodeh === "a" || hmodeh === "o" || hmodeh === "i" || hmodeh === "n") {
if (hmodeh === "a" || hmodeh === "i") {
tmp += "\\hline ";
}
} else {
var pattern = hmodeh.split(" ");
var second = pattern[1].split('');
for (var i = 0; i < second.length; ++i) {
switch (second[i]) {
case 'h':
tmp += "\\hline";
break;
case 'b':
break;
default:
alert("Unknown format character found! Format string was: " + hmodeh);
return;
}
}
tmp += " ";
}
// body
var pattern = hmode.split(" ");
var i = 0;
c = 0;
for ( var r in results) {
for ( var key in results[r]) {
tmp += results[r][key] + "&";
}
tmp = tmp.substring(0, tmp.length - 1) + "\\\\";
if (hmode === "a" || (hmode === "i" && c !== results.length - 1) || (hmode === "o" && c === results.length - 1)) {
tmp += "\\hline ";
} else if (hmode !== "a" && hmode !== "i" && hmode !== "o" && hmode !== "n") {
var format = pattern[i++ % pattern.length].split('');
for (var j = 0; j < format.length; ++j) {
switch (format[j]) {
case 'h':
tmp += "\\hline";
break;
case 'b':
break;
default:
alert("Unknown format character found! Format string was: " + hmodeh);
return;
}
}
tmp += " ";
}
++c;
}
tmp += "\\end{tabular}";
return tmp;
}
function buildContainerPivotBig(json, containerOver, initial) {
var basetextsize = 8;
var updateData = function() {
json.jsonBig.type.I.queryB = ref.editor.getValue();
// TODO: save pivot table settings (aggr, aggrAtt, renderer)
var r = getPivotTableData(json.jsonBig, true);
json.resultBig = r.res;
if (r.error != undefined) {
error.innerHTML = 'Query status: Error! ' + r.error;
containerOptions.style.visibility = 'hidden';
containerChart.style.visibility = 'hidden';
return;
} else {
error.innerHTML = 'Query status: OK';
containerOptions.style.visibility = 'visible';
containerChart.style.visibility = 'visible';
}
var aggr = r.aggr;
var aggrName = r.aggrName;
var aggrAtt = r.aggrAttribute;
$(containerContent).pivotUI(r.res, {
aggregator : aggr
}, true);
};
var viewerContainer = document.getElementById("viewerContainer");
json.jsonBig = jQuery.extend(true, {}, json);
var tip = "Tip: Drag and drop attributes to the row/column area.
";
var ref = prepopulateContainerOver(containerOver, viewerContainer, tip, [ json ], updateData, 'pivot table', false);
var containerContent = ref.containerContent;
var containerControl = ref.containerControl;
var containerChart = ref.containerChart;
var containerOptions = ref.options;
var editor = ref.editor;
var error = ref.error;
editor.setValue(prettifySQL(json.jsonBig.type.I.queryB));
var r = getPivotTableData(json.jsonBig, true);
json.resultBig = r.res;
if (r.error != undefined) {
error.innerHTML = 'Query status: Error! ' + r.error;
containerOptions.style.visibility = 'hidden';
containerChart.style.visibility = 'hidden';
return;
} else {
error.innerHTML = 'Query status: OK';
containerOptions.style.visibility = 'visible';
containerChart.style.visibility = 'visible';
}
var aggrName = r.aggrName;
var aggrAtt = r.aggrAttribute;
var aggr = $.pivotUtilities.aggregators[aggrName]([ aggrAtt ]);
$(containerContent).pivotUI(r.res, {
rows : r.rows,
cols : r.cols,
aggregator : aggr,
vals : [ aggrAtt ],
aggregatorName : aggrName
});
containerOver.update = updateData;
containerOver.updateData = updateData;
}
function buildContainerPivot(container, json, zoomFactor, style, containerOver) {
var chart = document.createElement('div');
chart.setAttribute('style', 'width:100%; height:100%;');
container.appendChild(chart);
container.setAttribute('style', style + "background: white;");
var r;
if (json.result == undefined) {
r = getPivotTableData(json, false);
if (r.error != undefined) {
alert(r.error);
return;
}
json.result = r;
} else {
r = json.result;
}
var aggrName = r.aggrName;
var aggrAtt = r.aggrAttribute;
if ($.pivotUtilities.aggregators[aggrName] == undefined) {
alert("Aggregator \"" + aggrName + "\" is not defined! Where: " + json.name);
}
var aggr = $.pivotUtilities.aggregators[aggrName]([ aggrAtt ]);
var unused = [];
for ( var key in r.res[0]) {
if (aggrAtt != key && $.inArray(key, r.rows) == -1 && $.inArray(key, r.cols) == -1) {
unused[unused.length] = key;
}
}
$(chart).pivot(r.res, {
rows : r.rows,
cols : r.cols,
aggregator : aggr,
unused : unused
});
container.getElementsByClassName("pvtTable")[0].setAttribute('style', 'width: 100%; height: 100%;');
}
function buildContainerTableBig(json, containerOver) {
var basetextsize = 8;
var update = function() {
json.jsonBig.type.I.queryB = ref.editor.getValue();
var err;
try {
var results = alasqlQuery(json.jsonBig.type.I.queryB);
json.resultBig = results;
} catch (e) {
err = e.message;
}
if (err == undefined) {
try {
getTableFromResults(results, containerContent);
} catch (e) {
err = e.message;
}
}
if (err != undefined) {
error.innerHTML = 'Query status: Error! ' + err;
containerOptions.style.visibility = 'hidden';
containerChart.style.visibility = 'hidden';
return;
} else {
error.innerHTML = 'Query status: OK';
containerOptions.style.visibility = 'visible';
containerChart.style.visibility = 'visible';
}
};
var viewerContainer = document.getElementById("viewerContainer");
var tip = 'Tip: Click on the attributes to change the sorting.';
json.jsonBig = jQuery.extend(true, {}, json);
var ref = prepopulateContainerOver(containerOver, viewerContainer, tip, [ json ], update, 'table', false);
var containerContent = ref.containerContent;
var containerOptions = ref.options;
var containerChart = ref.containerChart;
var error = ref.error;
var err;
try {
var results = alasqlQuery(json.jsonBig.type.I.queryB);
json.resultBig = results;
} catch (e) {
err = e.message;
}
if (err != undefined) {
error.innerHTML = 'Query status: Error! ' + err;
containerOptions.style.visibility = 'hidden';
containerChart.style.visibility = 'hidden';
return;
} else {
error.innerHTML = 'Query status: OK';
containerOptions.style.visibility = 'visible';
containerChart.style.visibility = 'visible';
}
ref.editor.setValue(prettifySQL(json.jsonBig.type.I.queryB));
getTableFromResults(results, containerContent);
containerOver.update = function() {
};
containerOver.updateData = update;
}
function buildContainerMultiplotChart(container, json, zoomFactor, style, containerOver) {
function getLeft(cur, json, td) {
var ret;
var div = document.createElement('div');
div.className = 'vertical-text';
div.setAttribute('style', 'width: ' + left + 'px;');
td.appendChild(div);
if (typeof cur == 'string' || cur instanceof String) {
td.setAttribute('rowspan', 1);
div.innerHTML = "
" + cur + "
";
ret = 1;
} else {
if (cur.c == undefined || cur.text == undefined) {
alert("leftArr of " + json.name + " has wrong format!\nShould be: [{text: \"...\", c:somenumber}, ...]\nBut it was: " + JSON.stringify(topArr));
}
td.setAttribute('rowspan', cur.c);
div.innerHTML = "" + cur.text + "
";
ret = cur.c;
}
return ret;
}
function getRight(cur, json, td) {
var ret;
var div = document.createElement('div');
div.className = 'vertical-text';
div.setAttribute('style', 'width: ' + right + 'px;');
td.appendChild(div);
if (typeof cur == 'string' || cur instanceof String) {
td.setAttribute('rowspan', 1);
div.innerHTML = "" + cur + "
";
ret = 1;
} else {
if (cur.c == undefined || cur.text == undefined) {
alert("rightArr of " + json.name + " has wrong format!\nShould be: [{text: \"...\", c:somenumber}, ...]\nBut it was: " + JSON.stringify(topArr));
}
td.setAttribute('rowspan', cur.c);
div.innerHTML = "" + cur.text + "
";
ret = cur.c;
}
return ret;
}
function getTop(cur, json, td) {
var ret;
if (typeof cur == 'string' || cur instanceof String) {
td.setAttribute('colspan', 1);
td.innerHTML = cur;
ret = 1;
} else {
if (cur.c == undefined || cur.text == undefined) {
alert("topArr of " + json.name + " has wrong format!\nShould be: [{text: \"...\", c:somenumber}, ...]\nBut it was: " + JSON.stringify(topArr));
}
td.setAttribute('colspan', cur.c);
td.innerHTML = cur.text;
ret = cur.c;
}
td.setAttribute('style', 'height: 1.5em; width: ' + w + 'px;');
return ret;
}
function getBottom(cur, json, td) {
var ret;
if (typeof cur == 'string' || cur instanceof String) {
td.setAttribute('colspan', 1);
td.innerHTML = cur;
ret = 1;
} else {
if (cur.c == undefined || cur.text == undefined) {
alert("bottomArr of " + json.name + " has wrong format!\nShould be: [{text: \"...\", c:somenumber}, ...]\nBut it was: " + JSON.stringify(topArr));
}
td.setAttribute('colspan', cur.c);
td.innerHTML = cur.text;
ret = cur.c;
}
td.setAttribute('style', 'height: 1.5em; width: ' + w + 'px;');
return ret;
}
style = "background: white;" + style;
container.setAttribute('style', style);
var overlay = container;
var xCount = json.type.I.xCount;
var yCount = json.type.I.yCount;
var xValues;
try {
xValues = JSON.parse(json.type.I.xValues);
} catch (e) {
alert("Parsing of xValues for " + json.name + " failed!\nError: " + e.message + "\nValue: " + json.type.I.xValues);
}
var yValues;
try {
yValues = JSON.parse(json.type.I.yValues);
} catch (e) {
alert("Parsing of yValues for " + json.name + " failed!\nError: " + e.message + "\nValue: " + json.type.I.yValues);
}
var leftArr;
if (json.type.I.leftArr === "auto") {
if (json.type.I.yUnitName != "") {
leftArr = [ {
text : json.type.I.yUnitName,
c : yCount
} ];
} else {
leftArr = [];
}
} else {
try {
leftArr = JSON.parse(json.type.I.leftArr);
} catch (e) {
alert("Parsing of leftArr for " + json.name + " failed!\nError: " + e.message + "\nValue: " + json.type.I.leftArr);
}
}
var rightArr;
if (json.type.I.rightArr === "auto") {
rightArr = [];
for (var i = 0; i < yValues.length; ++i) {
rightArr[rightArr.length] = {
text : yValues[i],
c : 1
};
}
} else {
try {
rightArr = JSON.parse(json.type.I.rightArr);
} catch (e) {
alert("Parsing of rightArr for " + json.name + " failed!\nError: " + e.message + "\nValue: " + json.type.I.rightArr);
}
}
var topArr;
if (json.type.I.topArr === "auto") {
topArr = [];
for (var i = 0; i < xValues.length; ++i) {
topArr[topArr.length] = {
text : xValues[i],
c : 1
};
}
} else {
try {
topArr = JSON.parse(json.type.I.topArr);
} catch (e) {
alert("Parsing of topArr for " + json.name + " failed!\nError: " + e.message + "\nValue: " + json.type.I.topArr);
}
}
var bottomArr;
if (json.type.I.bottomArr === "auto") {
if (json.type.I.xUnitName != "") {
bottomArr = [ {
text : json.type.I.xUnitName,
c : xCount
} ];
} else {
bottomArr = [];
}
} else {
try {
bottomArr = JSON.parse(json.type.I.bottomArr);
} catch (e) {
alert("Parsing of bottomArr for " + json.name + " failed!\nError: " + e.message + "\nValue: " + json.type.I.bottomArr);
}
}
var queryBackup = json.type.I.query;
var yFirst = json.type.I.yFirst;
var forceXequal = json.type.I.forceXequal;
var forceYequal = json.type.I.forceYequal;
if (xValues.length != xCount) {
alert("Length of xValues array does not match xCount!\nxValues has length " + xCount.length + " but xCount is " + xCount);
}
if (yValues.length != yCount) {
alert("Length of yValues array does not match yCount!\nyValues has length " + yCount.length + " but yCount is " + yCount);
}
if (((queryBackup.match(/\?/g) || []).length) != 2) {
alert("Query for multiplot must contain exactly 2 occurrences of \"?\"\nQuery was: " + queryBackup);
}
// TODO: right now only labels of one line height are supported!
var fontbasesize = 15;
var left = leftArr.length != 0 ? fontbasesize * zoomFactor * 1.6 : 0;
var right = rightArr.length != 0 ? fontbasesize * zoomFactor * 1.6 : 0;
var top = topArr.length != 0 ? fontbasesize * zoomFactor * 1.6 : 0;
var bottom = bottomArr.length != 0 ? fontbasesize * zoomFactor * 1.6 : 0;
var options = getChartOptions(json, zoomFactor, {});
var legend = options.legend.show ? fontbasesize * zoomFactor * 1.6 : 0;
var inner = document.createElement('table');
var charts = [];
inner.setAttribute('style', 'height: 100%; width: 100%; border-collapse: collapse; text-align:center;');
overlay.appendChild(inner);
inner.className = 'multiplot';
var css = document.createElement('style');
css.setAttribute('scoped', 'scoped');
overlay.appendChild(css);
css.innerHTML = '.multiplot td {padding:0;} .c3-tooltip td {padding:0.3em;}';
var overlaywidth = $(overlay).width();
var overlayheight = $(overlay).height();
var nextLeft = 0;
var nextRight = 0;
var h = Math.floor((overlayheight - top - bottom - legend - 1) / yCount);
var w = Math.floor((overlaywidth - left - right - 1) / xCount);
var style = 'width: ' + w + 'px;' + 'height: ' + h + 'px;';
var yExtent;
var xExtent = [];
var legendItems = [];
var colors = {};
// Calculate size of axis labels
var div = document.createElement('div');
div.setAttribute('style', style);
overlay.appendChild(div);
var cellquery = queryBackup;
if (yFirst) {
cellquery = cellquery.replace("?", yValues[0]);
cellquery = cellquery.replace("?", xValues[0]);
} else {
cellquery = cellquery.replace("?", xValues[0]);
cellquery = cellquery.replace("?", yValues[0]);
}
json.type.I.query = cellquery;
defaultChartOptions.noyticks = true;
defaultChartOptions.noxticks = true;
var chartdata;
if (json.result == undefined) {
json.result = [];
}
var chartdata = getChartData(json);
if (chartdata.error != undefined) {
alert(json.name + " has error:\n" + chartdata.error);
}
var options = getChartOptions(json, zoomFactor, chartdata.values, div);
delete options.axis.y.label;
delete options.axis.x.label;
options.legend.show = false;
var chart = c3.generate(options);
var pl = chart.pl();
var pb = chart.pb();
overlay.removeChild(div);
var div = document.createElement('div');
div.setAttribute('style', style);
overlay.appendChild(div);
var cellquery = queryBackup;
if (yFirst) {
cellquery = cellquery.replace("?", yValues[0]);
cellquery = cellquery.replace("?", xValues[0]);
} else {
cellquery = cellquery.replace("?", xValues[0]);
cellquery = cellquery.replace("?", yValues[0]);
}
json.type.I.query = cellquery;
defaultChartOptions.noyticks = false;
defaultChartOptions.noxticks = false;
if (json.result[0] == undefined) {
chartdata = getChartData(json);
if (chartdata.error != undefined) {
alert(json.name + " has error:\n" + chartdata.error);
}
chartdata = chartdata.values;
json.result[0] = chartdata;
} else {
chartdata = json.result[0];
}
var options = getChartOptions(json, zoomFactor, chartdata, div);
delete options.axis.y.label;
delete options.axis.x.label;
options.legend.show = false;
var chart = c3.generate(options);
var pl = chart.pl() - pl;
var pb = chart.pb() - pb;
overlay.removeChild(div);
// /////////////////////////////
var h = Math.floor((overlayheight - top - bottom - legend - pb - 1) / yCount);
var w = Math.floor((overlaywidth - left - right - pl - 1) / xCount);
if (top != 0) {
var tr = document.createElement('tr');
inner.appendChild(tr);
if (left != 0) {
var td = document.createElement('td');
tr.appendChild(td);
}
var cur = topArr.shift();
var td = document.createElement('td');
tr.appendChild(td);
getTop(cur, json, td);
$(td).css("padding-left", pl);
while (topArr.length != 0) {
var cur = topArr.shift();
var td = document.createElement('td');
tr.appendChild(td);
getTop(cur, json, td);
}
if (right != 0) {
var td = document.createElement('td');
tr.appendChild(td);
}
}
for (var y = 0; y < yCount; ++y) {
var tr = document.createElement('tr');
inner.appendChild(tr);
if (left != 0 && y == nextLeft) {
var cur = leftArr.shift();
var td = document.createElement('td');
tr.appendChild(td);
nextLeft += getLeft(cur, json, td);
if (y == yCount - 1) {
$(td).css("padding-bottom", pb);
}
}
for (var x = 0; x < xCount; ++x) {
var td = document.createElement('td');
tr.appendChild(td);
var cellInner = document.createElement('div');
td.appendChild(cellInner);
var cellquery = queryBackup;
if (yFirst) {
cellquery = cellquery.replace("?", yValues[y]);
cellquery = cellquery.replace("?", xValues[x]);
} else {
cellquery = cellquery.replace("?", xValues[x]);
cellquery = cellquery.replace("?", yValues[y]);
}
json.type.I.query = cellquery;
if (x % xCount != 0) {
defaultChartOptions.noyticks = true;
var style = 'width: ' + w + 'px;';
} else {
defaultChartOptions.noyticks = false;
var style = 'width: ' + (w + pl) + 'px;';
}
if (y % yCount != yCount - 1) {
defaultChartOptions.noxticks = true;
style += 'height: ' + h + 'px;';
} else {
defaultChartOptions.noxticks = false;
style += 'height: ' + (h + pb) + 'px;';
}
cellInner.setAttribute('style', style);
td.setAttribute('style', style);
var chartdata;
if (json.result[x + y * Math.max(xCount, yCount)] == undefined) {
chartdata = getChartData(json);
if (chartdata.error != undefined) {
alert(json.name + " has error:\n" + chartdata.error);
}
chartdata = chartdata.values;
json.result[x + y * Math.max(xCount, yCount)] = chartdata;
} else {
chartdata = json.result[x + y * Math.max(xCount, yCount)];
}
var options = getChartOptions(json, zoomFactor, chartdata, cellInner);
if (forceYequal) {
if (x != 0) {
// replace y extent
options.axis.y.min = yExtent[0];
options.axis.y.max = yExtent[1];
options.axis.y.padding = {
top : 0,
bottom : 0
};
}
}
if (forceXequal) {
if (y != 0) {
// replace x extent
options.axis.x.min = xExtent[x][0];
options.axis.x.max = xExtent[x][1];
options.axis.x.padding = {
left : 0,
right : 0
};
}
}
delete options.axis.y.label;
delete options.axis.x.label;
options.legend.show = false;
var chart = c3.generate(options);
charts[charts.length] = chart;
if (legend != 0) {
var a = options.data.keys.value;
for (var i = 1; i < a.length; ++i) {
if (legendItems.indexOf(a[i]) === -1) {
legendItems[legendItems.length] = a[i];
colors[a[i]] = chart.color(a[i]);
}
}
}
if (forceYequal) {
if (x == 0) {
// save y extent
yExtent = chart.yd();
}
}
if (forceXequal) {
if (y == 0) {
// save x extent
xExtent[x] = chart.xd();
}
}
}
if (right != 0 && y == nextRight) {
var cur = rightArr.shift();
var td = document.createElement('td');
tr.appendChild(td);
nextRight += getRight(cur, json, td);
if (y == yCount - 1) {
$(td).css("padding-bottom", pb);
}
}
}
if (bottom != 0) {
var tr = document.createElement('tr');
inner.appendChild(tr);
if (left != 0) {
var td = document.createElement('td');
tr.appendChild(td);
}
while (bottomArr.length != 0) {
var cur = bottomArr.shift();
var td = document.createElement('td');
tr.appendChild(td);
getBottom(cur, json, td);
}
if (right != 0) {
var td = document.createElement('td');
tr.appendChild(td);
}
}
if (legend != 0) {
var tr = document.createElement('tr');
inner.appendChild(tr);
if (left != 0) {
var td = document.createElement('td');
tr.appendChild(td);
}
var td = document.createElement('td');
tr.appendChild(td);
td.setAttribute('colspan', xCount);
d3.select(td).insert('div', '.chart').attr('class', 'legend').selectAll('span').data(legendItems).enter().append('span').attr('data-id', function(id) {
return id;
}).html(function(id) {
return "" + id;
}).on('mouseover', function(id) {
charts.forEach(function(c, i, a) {
c.focus(id);
});
}).on('mouseout', function(id) {
charts.forEach(function(c, i, a) {
legendItems.forEach(function(c2, i2, a2) {
c.revert(c2);
});
});
}).on('click', function(id) {
charts.forEach(function(c, i, a) {
c.toggle(id);
});
});
if (right != 0) {
var td = document.createElement('td');
tr.appendChild(td);
}
}
json.type.I.query = queryBackup;
defaultChartOptions.noxticks = false;
defaultChartOptions.noyticks = false;
}
function print(text) {
outputElm.innerHTML = text.replace(/\n/g, '
');
}
function error(e) {
console.log(e);
errorElm.setAttribute('style', "margin-top:5px;overflow: auto;");
errorElm.innerHTML = "" + e.message + "
";
}
function noerror() {
errorElm.innerHTML = "";
errorElm.setAttribute('style', "height:0px;");
}
function execute(commands) {
try {
tic();
var results = alasqlQuery(commands);
toc("Executing SQL");
tic();
getTableFromResults(results, outputElm);
toc("Displaying results");
} catch (e) {
error(e);
outputElm.innerHTML = "";
}
}
function tableCreate(res, table) {
var columns = [];
for ( var key in res[0]) {
columns[columns.length] = {
data : key,
title : key
};
}
$(table).dataTable({
data : res,
columns : columns,
destroy : true
});
}
function getTableFromResults(results, container) {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
if (typeof (results) == 'number') {
var span = document.createElement('span');
span.setAttribute('style', 'text-decoration: underline; font-weight: bold;');
span.innerHTML = 'Result for Query:';
container.appendChild(span);
container.appendChild(getSpacer());
var span = document.createElement('span');
span.innerHTML = 'Query executed successfully.';
container.appendChild(span);
} else {
for (var i = 0; i < results.length; ++i) {
if (typeof (results[i]) == 'number') {
var span = document.createElement('span');
span.setAttribute('style', 'text-decoration: underline; font-weight: bold;');
span.innerHTML = 'Result for Query' + (i + 1) + ':';
container.appendChild(span);
container.appendChild(getSpacer());
var span = document.createElement('span');
span.innerHTML = 'Query executed successfully.';
container.appendChild(span);
container.appendChild(getSpacer());
} else if (results[i] instanceof Array) {
var span = document.createElement('span');
span.setAttribute('style', 'text-decoration: underline; font-weight: bold;');
span.innerHTML = 'Result for Query' + (i + 1) + ':';
container.appendChild(span);
container.appendChild(getSpacer());
if (results[i].length > 0) {
var table = document.createElement('table');
table.cellpadding = 0;
table.cellspacing = 0;
table.border = 0;
table.className = 'display';
table.setAttribute('style', 'border: 1px solid black; margin-top: 5px;');
container.appendChild(table);
tableCreate(results[i], table);
} else {
var span = document.createElement('span');
span.innerHTML = 'No rows returned.';
container.appendChild(span);
}
} else {
var span = document.createElement('span');
span.setAttribute('style', 'text-decoration: underline; font-weight: bold;');
span.innerHTML = 'Result for Query:';
container.appendChild(span);
container.appendChild(getSpacer());
var table = document.createElement('table');
table.cellpadding = 0;
table.cellspacing = 0;
table.border = 0;
table.className = 'display';
table.setAttribute('style', 'border: 1px solid black; margin-top: 5px;');
container.appendChild(table);
tableCreate(results, table);
break;
}
}
if (results.length == 0) {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
var span = document.createElement('span');
span.setAttribute('style', 'text-decoration: underline; font-weight: bold;');
span.innerHTML = 'Result for Query:
No rows returned.';
container.appendChild(span);
return;
}
}
return tmp;
}
function execEditorContents() {
noerror();
var query = document.getElementById("SQLQuery");
query.style.visibility = 'visible';
query.style.opacity = 1;
execute(editorMain.getValue() + ';');
}
// var debugmode = 0;
window.addEventListener('keydown', function keydown(evt) {
switch (evt.keyCode) {
case 27: // 27 == 'ESC'
var tmp = document.getElementsByClassName("centerhv");
for (var i = 0; i < tmp.length; ++i) {
setTimeout(function(o) {
o.style.visibility = 'hidden';
}, 500, tmp[i]);
tmp[i].style.opacity = 0;
}
break;
}
});
function addClickCloseHandler(elem, o) {
elem.addEventListener('click', function(e) {
setTimeout(function(o) {
o.style.visibility = 'hidden';
o.style['z-index'] = -1;
}, 500, o);
o.style.opacity = 0;
});
}
var defaultChartOptions = {
noxticks : false,
noyticks : false,
legend : {
show : true
}
};
function getChartOptions(json, zoomFactor, values, chart) {
var options = {
bindto : chart,
data : values,
size : {
width : $(chart).width(),
height : $(chart).height()
},
axis : {
x : {
label : json.type.I.xUnitName,
tick : {
fit : false
},
},
y : {
label : json.type.I.yUnitName,
tick : {
fit : false
},
},
y2 : {
tick : {
fit : false
}
}
},
zoom : {
enabled : true,
rescale : false
},
point : {
show : json.type.I.drawPoints
},
subchart : {
show : json.type.I.showRangeSelector
},
completeScale : zoomFactor,
legend : {
position : 'bottom'
},
onresize : function() {
$(chart).css('max-height', "100%");
this.api.resize({
height : $(chart).height(),
width : $(chart).width()
});
},
};
jQuery.extend(true, options, defaultChartOptions);
try {
var addOpt = JSON.parse(json.type.I.options);
} catch (e) {
alert('Parsing of options for ' + json.name + ' failed. \nDid you forgot to enclose every field and value by ", or did your TeX program replace " by \'\'?\nRemember that the correct JSON String syntax is: "key": "value"\n JSON String was:\n' + json.type.I.options);
}
jQuery.extend(true, options, addOpt);
if (options.axis.x.label == '') {
delete options.axis.x.label;
}
if (options.axis.y.label == '') {
delete options.axis.y.label;
}
if (json.type.I.includeZero) {
options.axis.y.min = 0;
}
var defaultformat = function(v) {
return (v || v === 0) ? +v : "";
};
var funcsave = options.axis.y.tick.format;
funcsave = typeof funcsave == "function" ? optionsBig.axis.y.tick.format : defaultformat;
if (json.type.I.logScale) {
options.axis.y.tick.format = function(d) {
return funcsave(+Math.exp(d).toFixed(2));
};
}
switch (json.type.I.chartType) {
case 'Line':
case 'line':
if (json.type.I.fillGraph) {
options.data.type = 'area';
} else {
options.data.type = 'line';
}
break;
case 'Bar':
case 'bar':
options.data.type = 'bar';
break;
case 'SignaturePlot':
case 'signatureplot':
case 'compareToBest':
case 'comparetobest':
try {
options.data = compareToBest([ options.data ]);
options.axis.x.tick.format = function(x) {
return '' + (Math.round(x * 10000) / 100) + '%';
};
options.axis.y.tick.format = function(y) {
return '' + (Math.round(y * 10000) / 100) + '%';
};
} catch (e) {
alert(e);
}
break;
default:
alert('Unknown chart type. Type was: "' + json.type.I.chartType + '"');
}
if (values.json != undefined && (isNaN(values.json[0][values.x])) && (options == undefined || options.axis == undefined || options.axis.x == undefined || options.axis.x.type == undefined)) {
if (isValidDate(values.json[0][values.x])) {
options.axis.x.type = "timeseries";
} else {
options.axis.x.type = "category";
}
}
if (!($(chart).parent().children().last()[0] instanceof HTMLStyleElement)) {
// add scoped css
var css = document.createElement('style');
css.setAttribute('scoped', 'scoped');
$(chart).parent().append(css);
var cssText;
cssText += '.c3-line { '
cssText += 'stroke-width: ' + (zoomFactor) + 'px; '
cssText += '} '
cssText += '.c3-circle._expanded_ { '
cssText += ' stroke-width: ' + (zoomFactor) + 'px; '
cssText += ' stroke: white; '
cssText += ' } '
cssText += ' .c3-selected-circle { '
cssText += ' fill: white; '
cssText += ' stroke-width: ' + (2 * zoomFactor) + 'px; '
cssText += ' } '
cssText += ' .c3-target.c3-focused path.c3-line, .c3-target.c3-focused path.c3-step { '
cssText += ' stroke-width: ' + (2 * zoomFactor) + 'px; '
cssText += ' } '
cssText += ' .c3-legend-background { '
cssText += ' opacity: 0.75; '
cssText += ' fill: white; '
cssText += ' stroke: lightgray; '
cssText += ' stroke-width: ' + (zoomFactor) + '; '
cssText += ' } ';
css.innerHTML = cssText;
}
return options;
}
function prepopulateContainerOver(containerOver, viewerContainer, tip, jsonArr, update, f, fixed) {
var json = jsonArr[0]; // pass by reference
var containerChart = document.createElement('div');
var style;
if (fixed) {
style = 'width:66%; height:95%; -moz-border-radius: 1%; -webkit-border-radius: 1%; border-radius: 1%; padding:2%; background:white; margin:1%; margin-top:2em; display: inline-block; vertical-align:top; white-space: normal;';
} else {
style = '-moz-border-radius: 1%; -webkit-border-radius: 1%; border-radius: 1%; padding:2%; background:white; margin:1%; margin-top:2em; display: inline-block; vertical-align:top; white-space: normal;';
}
containerChart.setAttribute('style', style);
var containerControl = document.createElement('div');
containerControl.setAttribute('style', 'width:30%; -moz-border-radius: 1%; -webkit-border-radius: 1%; border-radius: 1%; padding:2%; background:white; margin:1%; margin-top:2em; display: inline-block; text-align: left; white-space: normal;');
var containerSwitch = document.createElement('div');
containerSwitch.setAttribute('style', 'margin-bottom:5px; display: inline-block; vertical-align:top;');
containerControl.appendChild(containerSwitch);
containerControl.appendChild(getSpacer());
containerControl.appendChild(getSpacer());
var containerTip = document.createElement('div');
containerTip.setAttribute('style', 'font-weight: bold;');
containerTip.innerHTML = tip;
containerControl.appendChild(containerTip);
containerControl.appendChild(getSpacer());
var header = document.createElement('span');
header.innerHTML = 'SQL Query for ' + f + ':
Tip: Press CTRL-Space for autocomplete.
Tip: Click outside of the editor area to execute a query.';
containerControl.appendChild(header);
var textareaWrapper = document.createElement('div');
containerControl.appendChild(textareaWrapper);
textareaWrapper.setAttribute('style', 'border: 1px solid black; margin-top: 3px; margin-bottom: 3px;');
var textarea = document.createElement('textarea');
textareaWrapper.appendChild(textarea);
var def = document.createElement('input');
def.type = 'button';
def.value = 'Restore Default';
def.setAttribute('style', 'font-size:inherit; white-space: normal;');
def.addEventListener('click', function() {
delete json.jsonBig;
json.jsonBig = jQuery.extend(true, {}, json);
while (containerOver.firstChild) {
containerOver.removeChild(containerOver.firstChild);
}
switch (json.type.C) {
case "pdbf.json.MultiplotChart":
case "pdbf.json.Chart":
buildContainerChartBig(json, containerOver, true);
break;
case "pdbf.json.Text":
case "pdbf.json.DataText":
case "pdbf.json.DataTable":
buildContainerTableBig(json, containerOver);
break;
case "pdbf.json.Pivot":
buildContainerPivotBig(json, containerOver, true);
break;
}
});
containerControl.appendChild(def);
containerControl.appendChild(getSpacer());
containerControl.appendChild(getSpacer());
var error = document.createElement('span');
containerControl.appendChild(error);
error.innerHTML = 'Query status: OK';
containerControl.appendChild(getSpacer());
var options = document.createElement('div');
containerControl.appendChild(options);
var download = document.createElement('input');
download.type = 'button';
download.value = 'Download query result as CSV';
download.setAttribute('style', 'font-size:inherit; white-space: normal;');
download.addEventListener('click', function() {
var cols = [];
for ( var key in json.resultBig[0]) {
cols[cols.length] = {
columnid : key
};
}
alasql.into.CSV('result.csv', {
headers : true
}, json.resultBig, cols);
});
options.appendChild(download);
options.appendChild(getSpacer());
options.appendChild(getSpacer());
if (fixed) {
var containerChartSub = document.createElement('div');
containerChartSub.setAttribute('style', 'width:100%; height:100%; max-height:100%; z-index:9999');
containerChart.appendChild(containerChartSub);
}
var containerClose = document.createElement('div');
containerClose.innerHTML = 'Click here to close this window (or press Escape) [X]';
containerClose.setAttribute('style', 'float:right; cursor: pointer; font-weight: bold;');
addClickCloseHandler(containerClose, containerOver);
containerOver.appendChild(containerClose);
var containerLabel = document.createElement('span');
containerLabel.innerHTML = 'Switch representation:
';
containerSwitch.appendChild(containerLabel);
if (json.type.C != 'pdbf.json.Pivot') {
var buttonChart = document.createElement('input');
buttonChart.type = 'button';
buttonChart.value = 'Chart';
buttonChart.setAttribute('style', 'font-size:inherit;');
buttonChart.addEventListener('click', function() {
while (containerOver.firstChild) {
containerOver.removeChild(containerOver.firstChild);
}
buildContainerChartBig(json, containerOver, false);
});
containerSwitch.appendChild(buttonChart);
containerSwitch.appendChild(document.createTextNode(' '));
}
var buttonPivot = document.createElement('input');
buttonPivot.type = 'button';
buttonPivot.value = 'Pivot Table';
buttonPivot.setAttribute('style', 'font-size:inherit;');
buttonPivot.addEventListener('click', function() {
while (containerOver.firstChild) {
containerOver.removeChild(containerOver.firstChild);
}
buildContainerPivotBig(json, containerOver, false);
});
containerSwitch.appendChild(buttonPivot);
containerSwitch.appendChild(document.createTextNode(' '));
var buttonTable = document.createElement('input');
buttonTable.type = 'button';
buttonTable.value = 'Table';
buttonTable.setAttribute('style', 'font-size:inherit;');
buttonTable.addEventListener('click', function() {
while (containerOver.firstChild) {
containerOver.removeChild(containerOver.firstChild);
}
buildContainerTableBig(json, containerOver);
});
containerSwitch.appendChild(buttonTable);
var center = document.createElement('center');
center.appendChild(containerControl);
center.appendChild(containerChart);
containerOver.appendChild(center);
viewerContainer.appendChild(containerOver);
var editor = CodeMirror.fromTextArea(textarea, {
mode : "text/x-sql",
indentWithTabs : true,
smartIndent : true,
lineNumbers : true,
lineWrapping : true,
matchBrackets : true,
viewportMargin : Infinity,
extraKeys : {
"Ctrl-Space" : "autocomplete"
}
});
editor.setValue(prettifySQL(json.type.I.query));
editor.on('blur', update);
$(".CodeMirror-cursor").text("");
if (json.type.C == 'pdbf.json.MultiplotChart') {
var xValues;
try {
xValues = JSON.parse(json.type.I.xValues);
} catch (e) {
alert("Parsing of xValues for " + json.name + " failed!\nError: " + e.message + "\nValue: " + json.type.I.xValues);
}
var yValues;
try {
yValues = JSON.parse(json.type.I.yValues);
} catch (e) {
alert("Parsing of yValues for " + json.name + " failed!\nError: " + e.message + "\nValue: " + json.type.I.yValues);
}
var multiControl = document.createElement('div');
multiControl.setAttribute('style', 'text-decoration: underline; display: inline-block; margin-bottom: 7px;');
multiControl.innerHTML = 'Multiplot Control:
';
var selectX = document.createElement('select');
selectX.setAttribute('style', 'display:inline-block; margin-bottom:3px;');
for (var x = 0; x < json.type.I.xCount; ++x) {
var option = document.createElement('option');
option.innerHTML = xValues[x];
selectX.appendChild(option);
}
multiControl.appendChild(selectX);
var br = document.createElement('br');
multiControl.appendChild(br);
var selectY = document.createElement('select');
selectY.setAttribute('style', 'display:inline-block; margin-bottom:3px;');
for (var y = 0; y < json.type.I.yCount; ++y) {
var option = document.createElement('option');
option.innerHTML = yValues[y];
selectY.appendChild(option);
}
multiControl.appendChild(selectY);
containerControl.appendChild(document.createElement('br'));
containerControl.appendChild(multiControl);
var selectArr = [];
for (var x = 0; x < json.type.I.xCount; ++x) {
selectArr[xValues[x]] = [];
for (var y = 0; y < json.type.I.yCount; ++y) {
var cellquery = json.type.I.query;
var yFirst = json.type.I.yFirst;
if (yFirst) {
cellquery = cellquery.replace("?", yValues[y]);
cellquery = cellquery.replace("?", xValues[x]);
} else {
cellquery = cellquery.replace("?", xValues[x]);
cellquery = cellquery.replace("?", yValues[y]);
}
selectArr[xValues[x]][yValues[y]] = cellquery;
}
}
$(selectX).change(function() {
var x = $(selectX).val();
var y = $(selectY).val();
json.jsonBig.type.I.query = selectArr[x][y];
json.jsonBig.type.I.queryB = selectArr[x][y];
editor.setValue(prettifySQL(json.jsonBig.type.I.query));
containerOver.updateData();
});
$(selectY).change(function() {
var x = $(selectX).val();
var y = $(selectY).val();
json.jsonBig.type.I.query = selectArr[x][y];
json.jsonBig.type.I.queryB = selectArr[x][y];
editor.setValue(prettifySQL(json.jsonBig.type.I.query));
containerOver.updateData();
});
var x = $(selectX).val();
var y = $(selectY).val();
json.jsonBig.type.I.query = selectArr[x][y];
json.jsonBig.type.I.queryB = selectArr[x][y];
editor.setValue(prettifySQL(json.jsonBig.type.I.query));
}
fixOverlaySize();
var ref = {
containerContent : fixed ? containerChartSub : containerChart,
containerOver : containerOver,
containerControl : containerControl,
containerChart : containerChart,
editor : editor,
error : error,
options : options
};
return ref;
}
function getSpacer() {
return document.createElement('br');
}
function getChartData(json) {
var results;
try {
results = alasqlQuery(json.type.I.query);
} catch (e) {
return {
error : e.message
};
}
var error;
if (results.length == 0) {
return {
error : "Query \"" + json.type.I.query + "\" returns empty result!"
};
}
if (results[0] instanceof Array) {
return {
error : "Query \"" + json.type.I.query + "\" contains multiple statements!"
};
}
var columns = [];
for ( var key in results[0]) {
columns[columns.length] = key;
}
var ret = {
values : {
x : columns[0],
json : results,
keys : {
value : columns
}
},
error : error,
res : results
};
// logscale
if (json.type.I.logScale == true) {
for (var i = 0; i < ret.values.json.length; i++) {
var logscaleValues = ret.values.json[i];
for (var series = 0; series < ret.values.keys.value.length; ++series) {
var logId = ret.values.keys.value[series];
if (logId == ret.values.x) {
continue;
}
var logVal = logscaleValues[logId];
if (isNaN(logVal)) {
throw "Error! Logscale is active and chart contains negative values!";
}
ret.values.json[i][logId] = Math.log(logVal);
}
}
}
return ret;
}
function getPivotTableData(json, isBig) {
var error;
var results;
try {
results = alasqlQuery(isBig ? json.type.I.queryB : json.type.I.query);
} catch (e) {
return {
error : e.message
};
}
if (results.length == 0) {
return {
error : "Query of " + (isBig ? json.name + 'Big' : json.name) + "returns empty result!\nQuery was: \"" + (isBig ? json.type.I.queryB : json.type.I.query) + "\""
};
}
if (results[0] instanceof Array) {
return {
error : "Query of " + (isBig ? json.name + 'Big' : json.name) + "returns multiple statements!\nQuery was: \"" + (isBig ? json.type.I.queryB : json.type.I.query) + "\""
};
}
try {
var rows = JSON.parse(json.type.I.rows);
} catch (e) {
return {
error : 'Parsing of rows for ' + (isBig ? json.name + 'Big' : json.name) + ' failed. \nDid you forgot to enclose every row by ", or did you TeX program replace " by \'\'?\n JSON String was:\n' + json.type.I.rows
};
}
try {
var cols = JSON.parse(json.type.I.cols);
} catch (e) {
return {
error : 'Parsing of cols for ' + (isBig ? json.name + 'Big' : json.name) + ' failed. \nDid you forgot to enclose every col by ", or did you TeX program replace " by \'\'?\n JSON String was:\n' + json.type.I.cols
};
}
for (var i = 0; i < rows.length; ++i) {
if (results[0][rows[i]] == undefined) {
return {
error : 'Rows attribute "' + rows[i] + '" for ' + (isBig ? json.name + 'Big' : json.name) + ' does not exist!'
};
}
}
for (var i = 0; i < cols.length; ++i) {
if (results[0][cols[i]] == undefined) {
return {
error : 'Cols attribute "' + cols[i] + '" for ' + (isBig ? json.name + 'Big' : json.name) + ' does not exist!'
};
}
}
var aggrAttribute = (isBig ? json.type.I.aggregationattributeBig : json.type.I.aggregationattribute);
if (aggrAttribute != '' && results[0][aggrAttribute] == undefined) {
return {
error : 'Aggregation attribute "' + aggrAttribute + '" for ' + (isBig ? json.name + 'Big' : json.name) + ' does not exist!'
};
}
var aggrName = (isBig ? json.type.I.aggregationBig : json.type.I.aggregation);
try {
var aggr = $.pivotUtilities.aggregators[aggrName]([ aggrAttribute ]);
} catch (e) {
return {
error : 'Aggregation function ' + aggrName + ' does not exist!'
};
}
return {
rows : rows,
cols : cols,
res : results,
error : error,
aggrAttribute : aggrAttribute,
aggrName : aggrName
};
}
function getFullscreenDiv() {
var fullscreen = document.createElement('div');
var rawZoomFactor = PDFViewerApplication.pdfViewer._currentScale;
fullscreen.setAttribute('style', 'z-index:4; position:absolute; opacity:0.3; -webkit-transition:opacity 200ms ease-out; -moz-transition:opacity 200ms ease-out; -o-transition:opacity 200ms ease-out; transition:opacity 200ms ease-out;');
fullscreen.innerHTML = "";
$(fullscreen).hover(function() {
this.style.opacity = 0.8;
}, function() {
this.style.opacity = 0.3;
});
return fullscreen;
}
function GRUBBS_FILTER(arr, alpha) {
var arr = arr.slice();
if (!Array.isArray(arr)) {
throw new Error("Argument of GRUBBS_FILTER is not an array!");
}
if (alpha == undefined) {
var alpha = 0.05;
}
while (true) {
var N = arr.length;
var t = jStat.studentt.inv((alpha) / (2 * N), N - 2);
var ZCrit = (N - 1) / Math.sqrt(N) * Math.sqrt((t * t) / (N - 2 + t * t));
var M = jStat.mean(arr);
var SD = jStat.stdev(arr, true);
var Z = undefined;
var Zindex = -1;
arr.forEach(function(e, i) {
var tmp = Math.abs(e - M) / SD;
if (Z == undefined || tmp > Z) {
Z = tmp;
Zindex = i;
}
});
var margin_of_error = MARGIN_OF_ERROR(arr);
var avg = MEAN(arr);
if (Z > ZCrit && margin_of_error / avg > 0.025) {
arr.splice(Zindex, 1);
} else {
break;
}
}
return arr;
}
alasql.fn.GRUBBS_FILTER = GRUBBS_FILTER;
function MEAN(arr) {
if (!Array.isArray(arr)) {
throw new Error("Argument of MEAN is not an array!");
}
return jStat.mean(arr);
}
alasql.fn.MEAN = MEAN;
function STDDEV_SAMP(arr) {
if (!Array.isArray(arr)) {
throw new Error("Argument of STDDEV_SAMP is not an array!");
}
return jStat.stdev(arr, true);
}
alasql.fn.STDDEV_SAMP = STDDEV_SAMP;
function MARGIN_OF_ERROR(arr, alpha) {
if (!Array.isArray(arr)) {
throw new Error("Argument of MARGIN_OF_ERROR is not an array!");
}
var stdev = jStat.stdev(arr, true);
if (alpha == undefined) {
var alpha = 0.05;
}
var n = arr.length;
return jStat.studentt.inv(1 - alpha / 2, n - 1) * stdev * Math.sqrt(n);
}
alasql.fn.MARGIN_OF_ERROR = MARGIN_OF_ERROR;
function CONF_INT(arr, alpha) {
if (!Array.isArray(arr)) {
throw new Error("Argument of CONF_INT is not an array!");
}
var MOE = alasql.fn.MARGIN_OF_ERROR(arr, alpha); // TODO: maybe remove
// null/undefined values?
var MEAN = alasql.fn.MEAN(arr); // TODO: maybe remove null/undefined values?
return [ MEAN - MOE, MEAN + MOE ]
}
alasql.fn.CONF_INT = CONF_INT;
function T_TEST(arr1, arr2, alpha) {
if (!Array.isArray(arr1)) {
throw new Error("Argument 1 of T_TEST is not an array!");
}
if (!Array.isArray(arr2)) {
throw new Error("Argument 2 of T_TEST is not an array!");
}
if (alpha == undefined) {
var alpha = 0.05;
}
if (arr1 == arr2)
return true;
var m1 = jStat.mean(arr1);
var m2 = jStat.mean(arr2);
var n1 = arr1.length;
var n2 = arr2.length;
var s1 = jStat.stdev(arr1, true);
var s2 = jStat.stdev(arr2, true);
var sp = Math.sqrt(((n1 - 1) * (s1 * s1) + (n2 - 1) * (s2 * s2)) / (n1 + n2 - 2));
var t = Math.abs((m1 - m2) / (sp * Math.sqrt(1 / n1 + 1 / n2)));
var df = n1 + n2 - 2;
var p = 2 - jStat.studentt.cdf(t, df) * 2;
return p >= alpha;
}
alasql.fn.T_TEST = T_TEST;
function WELCH_TEST(arr1, arr2, alpha) {
if (!Array.isArray(arr1)) {
throw new Error("Argument 1 of WELCH_TEST is not an array!");
}
if (!Array.isArray(arr2)) {
throw new Error("Argument 2 of WELCH_TEST is not an array!");
}
if (alpha == undefined) {
var alpha = 0.05;
}
if (arr1 == arr2)
return true;
var m1 = jStat.mean(arr1);
var m2 = jStat.mean(arr2);
var n1 = arr1.length;
var n2 = arr2.length;
var s1 = jStat.stdev(arr1, true);
var s2 = jStat.stdev(arr2, true);
var s1s1n1 = s1 * s1 / n1;
var s2s2n2 = s2 * s2 / n2;
var t = Math.abs((m1 - m2) / Math.sqrt(s1s1n1 + s2s2n2));
var df = ((s1s1n1 + s2s2n2) * (s1s1n1 + s2s2n2)) / (((s1s1n1 * s1s1n1) / (n1 - 1)) + ((s2s2n2 * s2s2n2) / (n2 - 1)));
var p = 2 - jStat.studentt.cdf(t, df) * 2;
return p >= alpha;
}
alasql.fn.WELCH_TEST = WELCH_TEST;
function compareToBest(valuesArr) {
var values = valuesArr[0]; // Call by reference
if (values.keys == undefined)
return values;
var keys = values.keys.value;
if (values.finished) {
return values;
}
if (keys.length > 1) {
throw new Error("compareToBest does only support one attribute");
}
values.x = "x";
var aname = keys[0];
keys[keys.length] = "x";
var runtimes = values.json;
if (Array.isArray(runtimes[0][aname])) {
var runtime_count = runtimes.length;
var means = [];
var min;
var min_int;
// calculate mean of each experiment, search minimum of conf. int. lower
// bounds
for (var i = 0; i < runtime_count; ++i) {
var cur = runtimes[i][aname];
means[i] = alasql.fn.MEAN(cur);
var ci = alasql.fn.CONF_INT(cur);
if (min_int == undefined || ci[0] < min_int[0]) {
min = i;
min_int = ci;
}
}
var distance = []; // distance from best experiment
for (var i = 0; i < runtime_count; ++i) {
// for t_bests the distance is set to 0
if (alasql.fn.WELCH_TEST(runtimes[min][aname], runtimes[i][aname])) {
distance[i] = 0;
} else {
distance[i] = means[i] - min_int[1];
if (distance[i] < 0) {
distance[i] = 0;
}
}
}
var slowDown = [];
distance.forEach(function(v, i) {
slowDown[i] = (distance[i] + min_int[1]) / min_int[1] - 1.0;
});
slowDown.sort(function(a, b) {
return a - b;
});
var res = [];
slowDown.forEach(function(v, i) {
res[i] = {
x : i / (runtime_count - 1)
};
res[i][aname] = slowDown[i];
});
values.json = res;
values.finished = true;
return values;
} else {
var runtime_count = runtimes.length;
var means = [];
var min;
var min_int;
// calculate mean of each experiment, search minimum of conf. int. lower
// bounds
for (var i = 0; i < runtime_count; ++i) {
var cur = runtimes[i][aname];
means[i] = cur;
var ci = [ cur, cur ];
if (min_int == undefined || ci[0] < min_int[0]) {
min = i;
min_int = ci;
}
}
var distance = []; // distance from best experiment
for (var i = 0; i < runtime_count; ++i) {
distance[i] = means[i] - min_int[1];
}
var slowDown = [];
distance.forEach(function(v, i) {
slowDown[i] = (distance[i] + min_int[1]) / min_int[1] - 1.0;
});
slowDown.sort(function(a, b) {
return a - b;
});
var res = [];
slowDown.forEach(function(v, i) {
res[i] = {
x : i / (runtime_count - 1)
};
res[i][aname] = slowDown[i];
});
values.json = res;
values.finished = true;
return values;
}
}
function alasqlQuery(q) {
var results = alasql(q);
return results;
}
function isInt(x) {
var y = parseInt(x, 10);
return !isNaN(y) && x == y && x.toString() == y.toString();
}
function prettifySQL(sql) {
return sql; // TODO: Currently we dont support pretty printing sql because
// pretty printing of alasql breaks quoted literals
}