mirror of https://github.com/CIRCL/AIL-framework
chg: [d3 js] add barchart_stack graph function
parent
311e6f4bd8
commit
142ac83472
|
@ -0,0 +1,154 @@
|
|||
//Requirement: - D3v5
|
||||
// - jquery
|
||||
// data input: var data = [{ date: "2024-02-21", down: 0, up: 0}, { date: "2024-02-22", down: 1, up: 3}]
|
||||
//
|
||||
|
||||
const barchart_stack = (container_id, data, options) => {
|
||||
|
||||
const defaults = {
|
||||
style: {
|
||||
stroke: "rgb(0, 0, 0)",
|
||||
strokeWidth: 2,
|
||||
strokeWidthHover: 4.5
|
||||
},
|
||||
margin: {top:20, right:90, bottom:55, left:0},
|
||||
width: 500,
|
||||
height: 500
|
||||
};
|
||||
|
||||
options = $.extend(true, defaults, options);
|
||||
|
||||
let width_graph = options.width - options.margin.left - options.margin.right;
|
||||
let height_graph = options.height - options.margin.top - options.margin.bottom;
|
||||
|
||||
let x = d3.scaleBand().rangeRound([0, width_graph]).padding(0.1);
|
||||
let y = d3.scaleLinear().rangeRound([height_graph, 0]);
|
||||
|
||||
let xAxis = d3.axisBottom(x);
|
||||
let yAxis = d3.axisLeft(y);
|
||||
|
||||
let color = d3.scaleOrdinal(d3.schemeSet3);
|
||||
|
||||
let svg = d3.select("#"+container_id).append("svg")
|
||||
.attr("viewBox", "0 0 "+width_graph+" "+options.height)
|
||||
.attr("width", options.width)
|
||||
.attr("height", options.height)
|
||||
.append("g")
|
||||
.attr("transform", "translate("+options.margin.left+","+options.margin.top+")");
|
||||
|
||||
// popover
|
||||
$('[data-toggle="popover"]').popover({
|
||||
placement: 'top',
|
||||
container: 'body',
|
||||
html : true,
|
||||
});
|
||||
|
||||
const mouseover = function(d) {
|
||||
$(this).popover({
|
||||
title: d.name,
|
||||
placement: 'top',
|
||||
container: 'body',
|
||||
trigger: 'manual',
|
||||
html : true,
|
||||
content: function() {
|
||||
return d.label + "<br/>num: " + d3.format(",")(d.value ? d.value: d.y1 - d.y0);
|
||||
}
|
||||
});
|
||||
$(this).popover('show')
|
||||
}
|
||||
const mouseleave = function(d) {
|
||||
$('.popover').each(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
|
||||
let labelVar = 'date';
|
||||
let varNames = d3.keys(data[0])
|
||||
.filter(function (key) { return key !== labelVar;});
|
||||
|
||||
data.forEach(function (d) {
|
||||
let y0 = 0;
|
||||
d.mapping = varNames.map(function (name) {
|
||||
return {
|
||||
name: name,
|
||||
label: d[labelVar],
|
||||
y0: y0,
|
||||
y1: y0 += +d[name]
|
||||
};
|
||||
});
|
||||
d.total = d.mapping[d.mapping.length - 1].y1;
|
||||
});
|
||||
|
||||
x.domain(data.map(function (d) { return (d.date); }));
|
||||
y.domain([0, d3.max(data, function (d) { return d.total; })]);
|
||||
|
||||
svg.append("g")
|
||||
.attr("class", "x axis")
|
||||
.attr("transform", "translate(0," + height_graph + ")")
|
||||
.call(xAxis)
|
||||
.selectAll("text")
|
||||
.style("fill", "steelblue")
|
||||
.attr("transform", "rotate(-18)" )
|
||||
//.attr("transform", "rotate(-40)" )
|
||||
.style("text-anchor", "end");
|
||||
|
||||
svg.append("g")
|
||||
.attr("class", "y axis")
|
||||
.call(yAxis)
|
||||
.append("text")
|
||||
.attr("transform", "rotate(-90)")
|
||||
.attr("y", 6)
|
||||
.attr("dy", ".71em")
|
||||
.style("text-anchor", "end");
|
||||
|
||||
let selection = svg.selectAll(".series")
|
||||
.data(data)
|
||||
.enter().append("g")
|
||||
.attr("transform", function (d) { return "translate(" + x((d.date)) + ",0)"; });
|
||||
|
||||
selection.selectAll("rect")
|
||||
.data(function (d) { return d.mapping; })
|
||||
.enter().append("rect")
|
||||
.attr("width", x.bandwidth())
|
||||
.attr("y", function (d) { return y(d.y1); })
|
||||
.attr("height", function (d) { return y(d.y0) - y(d.y1); })
|
||||
.style("fill", function (d) { return color(d.name); })
|
||||
.style("stroke", "grey")
|
||||
.on("mouseover", mouseover)
|
||||
.on("mouseout", mouseleave)
|
||||
|
||||
|
||||
data.forEach(function(d) {
|
||||
if(d.total != 0){
|
||||
svg.append("text")
|
||||
.attr("dy", "-.35em")
|
||||
.attr('x', x(d.date) + x.bandwidth()/2)
|
||||
.attr('y', y(d.total))
|
||||
.style("text-anchor", "middle")
|
||||
.text(d.total);
|
||||
}
|
||||
});
|
||||
|
||||
// drawLegend(varNames)
|
||||
let legend = svg.selectAll(".legend")
|
||||
.data(varNames.slice().reverse())
|
||||
.enter().append("g")
|
||||
.attr("transform", function (d, i) { return "translate(0," + i * 20 + ")"; });
|
||||
|
||||
legend.append("rect")
|
||||
.attr("x", width_graph)
|
||||
.attr("width", 10)
|
||||
.attr("height", 10)
|
||||
.style("fill", color)
|
||||
.style("stroke", "grey");
|
||||
|
||||
legend.append("text")
|
||||
.attr("x", width_graph - 2)
|
||||
.attr("y", 6)
|
||||
.attr("dy", ".35em")
|
||||
.style("text-anchor", "end")
|
||||
.text(function (d) { return d; });
|
||||
|
||||
return svg
|
||||
|
||||
}
|
|
@ -16,21 +16,9 @@
|
|||
<script src="{{ url_for('static', filename='js/moment.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery.daterangepicker.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/d3.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/d3/barchart_stack.js') }}"></script>
|
||||
|
||||
<style>
|
||||
.bar {
|
||||
fill: steelblue;
|
||||
}
|
||||
.bar:hover{
|
||||
fill: brown;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bar_stack:hover{
|
||||
cursor: pointer;
|
||||
}
|
||||
.popover{
|
||||
max-width: 100%;
|
||||
}
|
||||
.domain_name {
|
||||
display:inline-block;
|
||||
overflow: hidden;
|
||||
|
@ -103,6 +91,7 @@
|
|||
</div>
|
||||
|
||||
<h3>Month Stats:</h3>
|
||||
<div id="pie_chart_month"></div>
|
||||
<div id="barchart_type_month"></div>
|
||||
|
||||
</div>
|
||||
|
@ -145,19 +134,20 @@ $(document).ready(function(){
|
|||
$('#date-range-to-input').val(s2);
|
||||
}
|
||||
});
|
||||
chart.stackBarChart = barchart_type_stack("{{ url_for('crawler_splash.crawlers_last_domains_json') }}?type={{type}}", '#barchart_type');
|
||||
chart.stackBarChartMonth = barchart_type_stack("{{ url_for('crawler_splash.crawlers_last_domains_month_json') }}?type={{type}}", '#barchart_type_month');
|
||||
|
||||
chart.onResize();
|
||||
$(window).on("resize", function() {
|
||||
chart.onResize();
|
||||
});
|
||||
$.getJSON("{{ url_for('crawler_splash.crawlers_last_domains_json') }}?type={{type}}",
|
||||
function (data) {
|
||||
let div_width = $("#barchart_type").width();
|
||||
barchart_stack("barchart_type", data, {"width": div_width});
|
||||
}
|
||||
);
|
||||
|
||||
$('[data-toggle="popover"]').popover({
|
||||
placement: 'top',
|
||||
container: 'body',
|
||||
html : true,
|
||||
});
|
||||
$.getJSON("{{ url_for('crawler_splash.crawlers_last_domains_month_json') }}?type={{type}}",
|
||||
function (data) {
|
||||
let div_width = $("#barchart_type_month").width();
|
||||
barchart_stack("barchart_type_month", data, {"width": div_width});
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
|
@ -176,166 +166,3 @@ function toggle_sidebar(){
|
|||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
function barchart_type_stack(url, svg_id) {
|
||||
|
||||
var margin = {top: 20, right: 90, bottom: 55, left: 0},
|
||||
width = $(svg_id).width()
|
||||
width = width - margin.left - margin.right,
|
||||
height = 500 - margin.top - margin.bottom;
|
||||
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1);
|
||||
|
||||
var y = d3.scaleLinear().rangeRound([height, 0]);
|
||||
|
||||
var xAxis = d3.axisBottom(x);
|
||||
|
||||
var yAxis = d3.axisLeft(y);
|
||||
|
||||
var color = d3.scaleOrdinal(d3.schemeSet3);
|
||||
|
||||
var svg = d3.select(svg_id).append("svg")
|
||||
.attr("id", svg_id)
|
||||
.attr("viewBox", "0 0 "+width+" 500")
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.append("g")
|
||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
||||
|
||||
d3.json(url)
|
||||
.then(function(data){
|
||||
|
||||
var labelVar = 'date'; //A
|
||||
var varNames = d3.keys(data[0])
|
||||
.filter(function (key) { return key !== labelVar;}); //B
|
||||
|
||||
data.forEach(function (d) { //D
|
||||
var y0 = 0;
|
||||
d.mapping = varNames.map(function (name) {
|
||||
return {
|
||||
name: name,
|
||||
label: d[labelVar],
|
||||
y0: y0,
|
||||
y1: y0 += +d[name]
|
||||
};
|
||||
});
|
||||
d.total = d.mapping[d.mapping.length - 1].y1;
|
||||
});
|
||||
|
||||
x.domain(data.map(function (d) { return (d.date); })); //E
|
||||
y.domain([0, d3.max(data, function (d) { return d.total; })]);
|
||||
|
||||
svg.append("g")
|
||||
.attr("class", "x axis")
|
||||
.attr("transform", "translate(0," + height + ")")
|
||||
.call(xAxis)
|
||||
.selectAll("text")
|
||||
.attr("class", "bar")
|
||||
.on("click", function (d) { window.location.href = "#" })
|
||||
.attr("transform", "rotate(-18)" )
|
||||
//.attr("transform", "rotate(-40)" )
|
||||
.style("text-anchor", "end");
|
||||
|
||||
svg.append("g")
|
||||
.attr("class", "y axis")
|
||||
.call(yAxis)
|
||||
.append("text")
|
||||
.attr("transform", "rotate(-90)")
|
||||
.attr("y", 6)
|
||||
.attr("dy", ".71em")
|
||||
.style("text-anchor", "end");
|
||||
|
||||
var selection = svg.selectAll(".series")
|
||||
.data(data)
|
||||
.enter().append("g")
|
||||
.attr("class", "series")
|
||||
.attr("transform", function (d) { return "translate(" + x((d.date)) + ",0)"; });
|
||||
|
||||
selection.selectAll("rect")
|
||||
.data(function (d) { return d.mapping; })
|
||||
.enter().append("rect")
|
||||
.attr("class", "bar_stack")
|
||||
.attr("width", x.bandwidth())
|
||||
.attr("y", function (d) { return y(d.y1); })
|
||||
.attr("height", function (d) { return y(d.y0) - y(d.y1); })
|
||||
.style("fill", function (d) { return color(d.name); })
|
||||
.style("stroke", "grey")
|
||||
.on("mouseover", function (d) { showPopover.call(this, d); })
|
||||
.on("mouseout", function (d) { removePopovers(); })
|
||||
.on("click", function(d){ window.location.href = "#" });
|
||||
|
||||
|
||||
data.forEach(function(d) {
|
||||
if(d.total != 0){
|
||||
svg.append("text")
|
||||
.attr("class", "bar")
|
||||
.attr("dy", "-.35em")
|
||||
.attr('x', x(d.date) + x.bandwidth()/2)
|
||||
.attr('y', y(d.total))
|
||||
.on("click", function () {window.location.href = "#" })
|
||||
.style("text-anchor", "middle")
|
||||
.text(d.total);
|
||||
}
|
||||
});
|
||||
|
||||
drawLegend(varNames);
|
||||
});
|
||||
|
||||
|
||||
function drawLegend (varNames) {
|
||||
var legend = svg.selectAll(".legend")
|
||||
.data(varNames.slice().reverse())
|
||||
.enter().append("g")
|
||||
.attr("class", "legend")
|
||||
.attr("transform", function (d, i) { return "translate(0," + i * 20 + ")"; });
|
||||
|
||||
legend.append("rect")
|
||||
.attr("x", width)
|
||||
.attr("width", 10)
|
||||
.attr("height", 10)
|
||||
.style("fill", color)
|
||||
.style("stroke", "grey");
|
||||
|
||||
legend.append("text")
|
||||
.attr("class", "svgText")
|
||||
.attr("x", width - 2)
|
||||
.attr("y", 6)
|
||||
.attr("dy", ".35em")
|
||||
.style("text-anchor", "end")
|
||||
.text(function (d) { return d; });
|
||||
}
|
||||
chart.onResize = function () {
|
||||
//var aspect = width / height, chart = $("#thesvg");
|
||||
svg_g = $(svg_id)
|
||||
var targetWidth = svg_g.parent().width();
|
||||
svg_g.attr("width", targetWidth);
|
||||
svg_g.attr("height", targetWidth / 2);
|
||||
}
|
||||
|
||||
function removePopovers () {
|
||||
$('.popover').each(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
|
||||
function showPopover (d) {
|
||||
$(this).popover({
|
||||
title: d.name,
|
||||
placement: 'top',
|
||||
container: 'body',
|
||||
trigger: 'manual',
|
||||
html : true,
|
||||
content: function() {
|
||||
return d.label +
|
||||
"<br/>num: " + d3.format(",")(d.value ? d.value: d.y1 - d.y0); }
|
||||
});
|
||||
$(this).popover('show')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
window.chart = chart;
|
||||
|
||||
</script>
|
||||
|
|
Loading…
Reference in New Issue