|
<!DOCTYPE HTML> |
|
<html> |
|
<header> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.css"> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.theme.min.css"> |
|
<link rel="stylesheet" |
|
href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.css"/> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.gridster/0.5.6/jquery.gridster.min.css" /> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.css"/> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.css"/> |
|
<style> |
|
#available-series { |
|
float: left; |
|
width: auto; |
|
margin-right: 2%; |
|
padding: 5px; |
|
background-color: rgba(0, 0, 0, 0.2); |
|
transition: opacity 0.4s ease-in-out; |
|
cursor: move; |
|
cursor: grab; |
|
} |
|
|
|
#selected-series { |
|
float: left; |
|
width: auto; |
|
height: auto; |
|
min-height: 40px; |
|
min-width: 200px; |
|
margin-right: 2%; |
|
padding: 5px; |
|
background-color: rgba(0, 0, 0, 0.2); |
|
transition: opacity 0.4s ease-in-out; |
|
cursor: move; |
|
cursor: grab; |
|
} |
|
|
|
#available-charts { |
|
float: left; |
|
width: auto; |
|
margin-right: 2%; |
|
padding: 5px; |
|
background-color: rgba(0, 0, 0, 0.2); |
|
transition: opacity 0.4s ease-in-out; |
|
cursor: move; |
|
cursor: grab; |
|
overflow: scroll; |
|
} |
|
|
|
#chart-container { |
|
height: 100%; |
|
width: 100%; |
|
} |
|
|
|
ul { |
|
padding: 1px; |
|
} |
|
|
|
li { |
|
list-style: none; |
|
padding: 1px; |
|
margin: 1px; |
|
} |
|
|
|
.horizontal li { |
|
display: inline-block; |
|
} |
|
|
|
html, body, #main-table, #main-layout-table { |
|
width: 100%; |
|
height: 100%; |
|
} |
|
|
|
#widget-table { |
|
width: 100%; |
|
height: 100%; |
|
max-width: 100%; |
|
max-height: 100%; |
|
table-layout: fixed !important; |
|
} |
|
|
|
#widget-header { |
|
width: 100%; |
|
height: 20px; |
|
} |
|
|
|
#widget-header-left { |
|
width: 100%; |
|
height: 20px; |
|
background-color: #3e999f; |
|
} |
|
|
|
#widget-header-right { |
|
height: 20px; |
|
} |
|
|
|
#widget-content { |
|
width: 100%; |
|
height: 100%; |
|
} |
|
|
|
.btn:hover { |
|
opacity: .7 !important; |
|
} |
|
|
|
.gridster { |
|
width: 100%; |
|
height: 100%; |
|
} |
|
|
|
.gridster .gs-w { |
|
background: white; |
|
cursor: pointer; |
|
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); |
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); |
|
overflow: hidden; |
|
} |
|
|
|
.gridster .player { |
|
-webkit-box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); |
|
box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); |
|
background: #BBB; |
|
} |
|
|
|
.gridster .preview-holder { |
|
border: none !important; |
|
border-radius: 0 !important; |
|
background: red !important; |
|
} |
|
|
|
.gridster ul { |
|
background-color: #EFEFEF; |
|
padding-left: 0px; |
|
width: 100% !important; |
|
min-height: 100px !important; |
|
} |
|
|
|
.gridster li { |
|
font-size: 1em; |
|
font-weight: bold; |
|
text-align: center; |
|
line-height: 100%; |
|
} |
|
|
|
ul { |
|
list-style-type: none; |
|
} |
|
|
|
li { |
|
list-style: none; |
|
font-weight: bold; |
|
} |
|
|
|
/* Disable the mirror when interacting with the dex charts */ |
|
.gu-mirror { |
|
display: none !important; |
|
} |
|
|
|
/* Treemap styling */ |
|
.TreemapClass text { |
|
pointer-events: none; |
|
} |
|
|
|
.TreemapClass .grandparent text { |
|
font-weight: bold; |
|
} |
|
|
|
.TreemapClass rect { |
|
fill: none; |
|
stroke: #fff; |
|
} |
|
|
|
.TreemapClass rect.parent, |
|
.grandparent rect { |
|
stroke-width: 2px; |
|
} |
|
|
|
.TreemapClass .grandparent rect { |
|
fill: steelblue; |
|
} |
|
|
|
.grandparent:hover rect { |
|
fill: #ee9700; |
|
} |
|
|
|
.TreemapClass .children rect.parent, |
|
.grandparent rect { |
|
cursor: pointer; |
|
} |
|
|
|
.TreemapClass .children rect.parent { |
|
fill-opacity: .1; |
|
} |
|
|
|
.TreemapClass .children:hover rect.child { |
|
fill-opacity: .8; |
|
} |
|
</style> |
|
</header> |
|
<body> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/js/bootstrap.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> |
|
<script src="https://dexjs.net/js/dex.js"></script> |
|
<script>d3 = dex.charts.d3.d3v3;</script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.js"></script> |
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.gridster/0.5.6/jquery.gridster.min.js"></script> |
|
<table id="main-table"> |
|
<tr> |
|
<td valign="top" width="120px"> |
|
<ul id="available-series"></ul> |
|
</td> |
|
<td valign="top"> |
|
<table id="main-layout-table"> |
|
<tr> |
|
<td valign="top" height="50px"> |
|
<ul class="horizontal" id="selected-series"></ul> |
|
</td> |
|
</tr> |
|
<tr> |
|
<td width="100%" halign="left"> |
|
<div class="gridster"> |
|
<ul id="chart-container"></ul> |
|
</div> |
|
</td> |
|
</tr> |
|
</table> |
|
</td> |
|
<td valign="top" width="120px" height="100%"> |
|
<ul> |
|
<ul id="available-charts"></ul> |
|
</ul> |
|
</td> |
|
</tr> |
|
</table> |
|
<script> |
|
var csv = { |
|
'header': ['i', 'x', 'y', 'a', 'b', 'c'], |
|
'data': dex.datagen.randomIndexedIntegerMatrix({ |
|
rows: 20, columns: 6, min: 0, max: 20 |
|
}) |
|
}; |
|
|
|
var colorScheme = d3.scale.category20c(); |
|
var chartCsv = {}; |
|
var selectedSeries = []; |
|
var charts = []; |
|
var gridster; |
|
var gridsterConfig = { |
|
widget_base_dimensions: [50, 50], |
|
widget_margins: [1, 1], |
|
//helper: 'clone', |
|
animate: false, |
|
draggable: { |
|
enabled: true, |
|
start: function (e, ui) { |
|
dex.console.log("DRAG-START", e, ui); |
|
}, |
|
handle: '.drag-handle' |
|
}, |
|
resize: { |
|
enabled: true, |
|
min_size: [1, 1], |
|
stop: function (event, ui, $widget) { |
|
dex.console.log("Event", event, ui, $widget); |
|
charts.forEach(function (chartGroup) { |
|
if (chartGroup instanceof Array) { |
|
chartGroup.forEach(function (chart) { |
|
chart.resize(); |
|
}) |
|
} |
|
else { |
|
chartGroup.resize(); |
|
} |
|
}); |
|
} |
|
} |
|
}; |
|
|
|
d3.json("charts.json", function (error, availableCharts) { |
|
var chartLookup = {}; |
|
availableCharts.forEach(function (chart) { |
|
chartLookup[chart.configuration.name] = chart.configuration; |
|
}); |
|
|
|
d3.select("#available-series") |
|
.selectAll("li") |
|
.data(csv.header) |
|
.enter() |
|
.append("li") |
|
.append("button") |
|
.attr("type", "button") |
|
.attr("class", "btn") |
|
.style("width", "100px") |
|
.style("color", "white") |
|
.style("border-color", "white") |
|
.style("background-color", function (d) { |
|
return colorScheme(d); |
|
}) |
|
.html(function (d) { |
|
return d; |
|
}); |
|
|
|
d3.select("#available-charts") |
|
.selectAll("li") |
|
.data(availableCharts) |
|
.enter() |
|
.append("li") |
|
.append("img") |
|
.attr("src", function (d) { |
|
return d.image; |
|
}) |
|
.attr("alt", function (d) { |
|
return d.configuration.name; |
|
}) |
|
.attr("height", 60) |
|
.attr("width", 100) |
|
.style("border", 0); |
|
|
|
// Handle adding series. |
|
var addSeriesDrake = dragula([document.getElementById("available-series"), document.getElementById("selected-series")], { |
|
copy: true, |
|
direction: 'horizontal', |
|
removeOnSpill: true |
|
}); |
|
|
|
// Handle drop event for adding a series. |
|
addSeriesDrake.on('drop', function (el, target, src, sibling) { |
|
dex.console.log("drop-add-series", el, target, src, sibling); |
|
selectedSeries = $("#selected-series li").map(function () { |
|
return $(this).text(); |
|
}).get(); |
|
//dex.console.log("SELECTED-SERIES", selectedSeries); |
|
chartCsv = dex.csv.columnSlice(csv, selectedSeries); |
|
//dex.console.log("CHART-CSV", chartCsv); |
|
charts.forEach(function (chartGroup) { |
|
if (chartGroup instanceof Array) { |
|
chartGroup.forEach(function (chart) { |
|
//dex.console.log("Updating chart: " + chart.attr("id")); |
|
//dex.console.log("chartcsv", chartCsv); |
|
chart.attr("csv", chartCsv).update(); |
|
}); |
|
} |
|
else { |
|
//dex.console.log("Updating chart: " + chartGroup.attr("id")); |
|
//dex.console.log("chartcsv", chartCsv); |
|
chartGroup.attr("csv", chartCsv).update(); |
|
} |
|
}); |
|
}); |
|
|
|
// Support for removing a series. |
|
var removeSeriesDrake = dragula([document.getElementById("selected-series")], { |
|
removeOnSpill: true |
|
}); |
|
|
|
removeSeriesDrake.on('remove', function (el, target, src, sibling) { |
|
selectedSeries = $("#selected-series li").map(function () { |
|
return $(this).text(); |
|
}).get(); |
|
|
|
//dex.console.log("DESELECTED-SERIES", selectedSeries); |
|
|
|
chartCsv = dex.csv.columnSlice(csv, selectedSeries); |
|
//dex.console.log("CHART-CSV", chartCsv); |
|
charts.forEach(function (chartGroup) { |
|
if (chartGroup instanceof Array) { |
|
chartGroup.forEach(function (chart) { |
|
chart.attr("csv", chartCsv).update(); |
|
}) |
|
} |
|
else { |
|
chartGroup.attr("csv", chartCsv).update(); |
|
} |
|
}); |
|
}); |
|
|
|
var addChartDrake = dragula([document.getElementById("available-charts"), |
|
document.getElementById("chart-container")], { |
|
copy: true, |
|
removeOnSpill: true, |
|
}); |
|
addChartDrake.on('drop', function (el, target, src, sibling) { |
|
// Cancel normal dragula drag and drop, we will handle it. |
|
addChartDrake.cancel(true); |
|
|
|
selectedSeries = $("#selected-series li").map(function () { |
|
return $(this).text(); |
|
}).get(); |
|
|
|
if (selectedSeries.length < 2) { |
|
alert("You must select at least 2 series before you may select a chart."); |
|
return; |
|
} |
|
|
|
var chartId = el.childNodes[0].alt; |
|
var parentId = chartId + "Parent" + charts.length; |
|
var chartConfig = chartLookup[chartId]; |
|
|
|
var widget = "<li><table id='widget-table' style='word-break:break-all;'>" + |
|
"<tr id='widget-header'><td id='widget-header-left' class='drag-handle'>|||</td>" + |
|
"<td id='widget-header-right'><button type='button' class='btn gridster-remove' " + |
|
"id='close-chart-button' style='font-size: 100%; " + |
|
"text-align: top; float: right;'>X</button></td></tr>" + |
|
"<tr><td id='widget-content' colspan='2'><div id='" + parentId + "' height='100%'" + |
|
" width='100%'></div></td></tr></table></li>" |
|
|
|
gridster.add_widget(widget, 5, 5); |
|
|
|
var components = dex.create(chartConfig); |
|
var chartNum = 1; |
|
var parent = d3.select("#" + parentId); |
|
components.forEach(function (chart) { |
|
parent.append("div") |
|
.style("height", "90%") |
|
.style("width", "100%") |
|
.attr("id", parentId + "_" + chartNum); |
|
chart.attr("parent", "#" + parentId + "_" + chartNum); |
|
chart.attr("id", chartId + "Id_" + chartNum); |
|
chart.attr("csv", chartCsv); |
|
chart.render(); |
|
chartNum++; |
|
}); |
|
charts.push(components); |
|
}); |
|
}); |
|
|
|
$(document).ready(function () { |
|
gridster = $(".gridster ul") |
|
.gridster(gridsterConfig) |
|
.data('gridster'); |
|
|
|
$(document).on("click", "#close-chart-button", function () { |
|
dex.console.log("CLOSING", $(this)); |
|
gridster.remove_widget($(this).closest('li')); |
|
|
|
// REM: Timing issue. Update the charts list after giving |
|
// gridster a second to remove the widget. |
|
setTimeout(function () { |
|
charts.forEach(function (chartGroup, i) { |
|
var parentId; |
|
if (chartGroup instanceof Array) { |
|
parentId = chartGroup[0].attr("parent"); |
|
if ($(parentId).length == 0) { |
|
chartGroup.forEach(function(chart) { chart.deleteChart(); }); |
|
charts.splice(i, 1); |
|
return; |
|
} |
|
} |
|
else { |
|
parentId = chartGroup.attr("parent"); |
|
if ($(parentId).length == 0) { |
|
chartGroup.deleteChart(); |
|
charts.splice(i, 1); |
|
return; |
|
} |
|
} |
|
}); |
|
}, 1000); |
|
}); |
|
}); |
|
</script> |
|
</body> |
|
</html> |