factorize stylesheets and js from templates (fixes #12734)

This commit is contained in:
Benjamin Dauvergne 2016-07-23 09:35:58 +02:00
parent fb23c28f1f
commit 6cec6f382c
9 changed files with 571 additions and 400 deletions

View File

@ -3,4 +3,4 @@ include VERSION
include tox.ini
recursive-include tests *.py
recursive-include bijoe/templates *.html
recursive-include bijoe/static *.js
recursive-include bijoe/static *.js *.css

147
bijoe/static/css/bijoe.css Normal file
View File

@ -0,0 +1,147 @@
/* Printing */
@media print {
/* hide UI */
#top, #header, #more-user-links, .download, #content form {
display: none;
}
/* resize content */
#data {
width: 100%;
}
}
/* Breadcrumb */
#bijoe-slice-url-span {
text-overflow: ellipsis;
display: inline-block;
max-width: 30em;
white-space: nowrap;
overflow: hidden;
line-height: 15px;
}
/* Cube form */
/* make a form a column on the right if not on mobile */
@media screen and (min-width: 800px) {
form {
float: right;
width: 20em;
padding-left: 2em;
}
}
/* size daterange fields in order to fit on one line inside the right column */
input[type=date] {
width: calc(100% / 2 - 8px);
}
select {
width: 100%;
}
form p { /* reduce spacing between fields */
margin-bottom: 0.5ex;
}
form h3 { /* reduce spacing between field groups headers */
margin-top: 0.5ex;
margin-bottom: 0.5ex;
}
/* work-around too genereic css rule in gadjo incompatible with jquery-ui style */
.ui-datepicker select {
padding-right: 0px;
}
/* add some between range field's subfields */
#id_filter__receipt_time_1 {
margin-left: 16px;
}
/* display representation field as an horizontal list of radio buttons */
#id_representation {
list-style: none;
padding: 0px;
text-align: justify;
display: flex;
justify-content: space-around;
}
/* put ODS export export slightly on the right of the repesentation header */
#ods {
margin: 1ex;
top: -2ex;
}
/* Main content */
/* size main content to let some place on the right for the form */
@media screen and (min-width: 800px) {
#data {
width: calc(100% - 23em);
}
}
/* table representation */
#data table {
width: 100%;
/* does not user normal table borders */
border-collapse: collapse;
/* increase line height */
line-height: 1.3em;
}
/* align measure columns to the right */
#data .bijoe-measure {
text-align: right;
}
#data .bijoe-drilldown {
text-align: left;
}
/* center cells vertically */
#data td {
vertical-align: middle;
}
/* add some spacing around data */
#data td, #data th {
padding-left: 1ex;
padding-right: 1ex;
padding-top: 3px;
padding-bottom: 3px;
}
/* highlight data rows on hover */
tbody tr:nth-child(even):hover td:not([rowspan]) {
background: #F1F1F1;
}
tbody tr:nth-child(odd):hover td:not([rowspan]) {
background: #F1F1F1;
}
tbody tr:nth-child(even) td:not([rowspan]) {
background: lightgrey;
}
/* chart representation */
.bijoe-png-button {
/* move PNG button slightly inside the chart frame */
float: right;
bottom: -3em;
left: -2em;
position: relative;
}
/* misc */
.bijoe-button {
background: #aaaaaa linear-gradient(to bottom, #f9f9f9, #eeeeee) repeat scroll 0 0;
border: 1px solid #b7b7b7;
border-radius: 1px;
box-shadow: 0 2px 2px 0 #ddd;
color: #424258;
cursor: pointer;
line-height: 100%;
padding: 1ex 2ex;
text-decoration: none;
}

301
bijoe/static/js/bijoe.js Normal file
View File

@ -0,0 +1,301 @@
/* Utility functions */
function capfirst(a) {
if (! a.length) {
return a;
}
if (a.charCodeAt(0) > 96 && a.charCodeAt(0) < 123) {
return String.fromCharCode(a.charCodeAt(0) - 32) + a.slice(1);
}
}
function human_join(a) {
/* Build french string for an enumeration */
if (a.length == 0) {
return '';
}else if (a.length == 1) {
return a[0].toString();
} else {
return a.slice(0, -1).join(', ') + ' et ' + a.slice(-1)[0];
}
}
function wrap_text(s, width) {
/* Wrap text after width characters */
var words = s.split(" ");
var s = "";
var l = 0;
for (var i = 0; i < words.length; i++) {
l += 1 + words[i].length;
if (l > width) {
s = s + "\n";
l = words[i].length;
} else {
s = s + " ";
}
s = s + words[i];
}
return s;
}
function spaced_hsla(i, n, s, l, a) {
/* Compute a specific color in a hue gradient in hsla colorspace, used to generate color maps for
* charts. */
var h = 360 * i/n;
return "hsla(" + h.toString() + ', ' + s.toString() + '%, ' + l.toString() + '%, ' + a.toString() + ')';
};
function toDataURL(canvas, filename) {
/* Convert a canvas to a PNG image with a white background, and generate a data url for it */
/* Temporary canvas with white background to print original canvas over */
destinationCanvas = document.createElement("canvas");
destinationCanvas.width = canvas.width;
destinationCanvas.height = canvas.height;
destCtx = destinationCanvas.getContext('2d');
// create a rectangle with the desired color
destCtx.fillStyle = "#FFFFFF";
destCtx.fillRect(0, 0, canvas.width, canvas.height);
// draw the original canvas onto the destination canvas
destCtx.drawImage(canvas, 0, 0);
var data = destinationCanvas.toDataURL("image/png");
data = data.split(";", 2)[1];
data = "data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=" + filename + ";" + data;
return data
}
var defaul_cn_options = {
/* Default ChartNew.js options */
animationSteps: 10,
/* Adapt graph to change in layout */
responsive: true,
/* Re-scale font based on responsive relayout */
responseScaleContent: true,
/* Show legend describing each color */
legend: true,
/* Start animation immediately do not wait for the chart to be visible */
dynamicDisplay: false,
/* Mimimum interval between y-axis ticks */
yAxisMinimumInterval: 10,
/* Show label on bars/points */
inGraphDataShow: true,
/* Set legend text color to black */
legendFontColor: "rgb(0,0,0,1)",
/* Set axis text color to black */
scaleFontColor: "rgb(0,0,0,1)",
/* Round number to two decimals */
roundNumber: -2,
/* Display data title when mouse is over the chart */
annotateDisplay : true,
/* Label do display on scale */
scaleLabel: "<%=value%>",
/* Set style for axis texts */
scaleFontSize : 16,
/* Display border around charts */
canvasBorders : true,
/* Set style of graph title */
graphTitleFontFamily : "'Arial'",
graphTitleFontSize : 24,
graphTitleFontStyle : "bold",
graphTitleFontColor : "#666",
/* Set style of footnote text (only used in piecharts) */
footNoteFontSize: 16,
}
function draw_piechart(canvas, dimensions, measures, measure, data) {
/* Draw piechart given a cavans element, a list of dimensions, a list of measure, the name of the
* measure to represent and data rows containing in the same order the dimensions and measures
* values */
var datasets = [];
var linedata = {datasets: datasets};
linedata.labels = [""];
var empty = []
var n = dimensions.length;
var option = $.extend({}, defaul_cn_options);
var ctx = canvas.getContext("2d");
for (var j = 0; j < measures.length; j++) {
if (measures[j].name == measure) {
break;
}
}
if (j == measures.length) {
// measure not found
return;
}
option.graphTitle = wrap_text(
capfirst(measures[j].label) + " par " + human_join(dimension_labels), 30)
/* Build one dataset by measurement, it's the way the piecharts expects it. */
var n = data.length;
for (var i = 0; i < n; i++) {
var value = data[i].measures[j].value;
var title = [];
for (var k = 0; k < data[i].coords.length; k++) {
title.push(data[i].coords[k].value);
}
title = title.join();
if (value > 1) {
dataset = {
data: [value],
title: title,
fillColor: spaced_hsla(i, n, 100, 30, 0.5),
strokeColor: spaced_hsla(i, n, 100, 30, 0.75),
highlightFill: spaced_hsla(i, n, 100, 30, 0.75),
highlightStroke: spaced_hsla(i, n, 100, 30, 1)
};
datasets.push(dataset);
} else {
/* push empty pie slices to the empty array */
empty.push(title);
}
}
/* show only percentages */
option.inGraphDataTmpl = "<%=v1+' '+v6+' %'%>";
option.annotateLabel = "<%=v1+' '+v6+' %'%>";
/* sort pie by slice size */
datasets.sort(function (a, b) {
return a.value - b.value;
});
/* if some slices are empty or nearly empty, do not try to show them in the piechart but add a
* footnore */
if (empty.length) {
option.footNote = wrap_text("Les valeurs pour " + human_join(empty)
+ " sont nulles ou presque.", 110);
}
new Chart(ctx).Pie(linedata, option);
}
function draw_barchart(canvas, dimensions, measures, measure, data) {
/* Draw bar chart given a cavans element, a list of dimensions, a list of measure, the name of the
* measure to represent and data rows containing in the same order the dimensions and measures
* values */
var dataset = {
data: [],
title: "",
fillColor: [],
strokeColor: [],
highlightFill: [],
highlightStroke: []
}
var datasets = [dataset];
var linedata = {labels: [], datasets: datasets};
var empty = []
var n = dimensions.length;
var option = $.extend({}, defaul_cn_options);
var ctx = canvas.getContext("2d");
for (var j = 0; j < measures.length; j++) {
if (measures[j].name == measure) {
break;
}
}
if (j == measures.length) {
// measure not found
return;
}
measure = measures[j]
dataset.title = measures[j].label;
option.graphTitle = wrap_text(
capfirst(measures[j].label) + " par " + human_join(dimension_labels), 30)
var n = data.length;
for (var i = 0; i < n; i++) {
var row = data[i];
var title = [];
for (var k = 0; k < data[i].coords.length; k++) {
title.push(data[i].coords[k].value);
}
title = title.join();
linedata.labels.push(title)
console.log(i, n);
dataset.data.push(row.measures[j].value);
dataset.fillColor.push(spaced_hsla(i, n, 100, 30, 0.5));
dataset.strokeColor.push(spaced_hsla(i, n, 100, 30, 0.75));
dataset.highlightFill.push(spaced_hsla(i, n, 100, 30, 0.75));
dataset.highlightStroke.push(spaced_hsla(i, n, 100, 30, 1));
}
if (measure.name.indexOf("delay") != -1) {
option.yAxisLabel = "jours";
}
if (measure.name == "count") {
option.yAxisLabel = "quantité";
}
if (measure.name == "percent") {
option.yAxisLabel = "pourcentage";
}
$.extend(option, {
//Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
scaleBeginAtZero : true,
//Boolean - Whether grid lines are shown across the chart
scaleShowGridLines : true,
//String - Colour of the grid lines
scaleGridLineColor : "rgba(0,0,0,.05)",
//Number - Width of the grid lines
scaleGridLineWidth : 1,
//Boolean - Whether to show horizontal lines (except X axis)
scaleShowHorizontalLines: true,
//Boolean - Whether to show vertical lines (except Y axis)
scaleShowVerticalLines: true,
//Boolean - If there is a stroke on each bar
// barShowStroke : true,
//Number - Pixel width of the bar stroke
barStrokeWidth : 2,
//Number - Spacing between each of the X value sets
barValueSpacing : 5,
//Number - Spacing between data sets within X values
barDatasetSpacing : 1,
});
console.log(linedata);
new Chart(ctx).Bar(linedata, option);
}
/* jQuery event handlers and widget setup */
$(function () {
/* Setup datepicker on input fields */
$('input[type=date]').datepicker({
dateFormat: 'yy-mm-dd',
changeMonth: true,
changeYear: true,
},
$.datepicker.regional['fr']);
/* Submit after 300ms on any change to form input */
$('input, select').on('change', function () {
setTimeout(function () {
$('form').ajaxSubmit({success: function (data) {
var $content = $(data);
$('#data').replaceWith($content.find('#data'));
$('#breadcrumb').replaceWith($content.find('#breadcrumb'));
location.hash = 'data';
}});
}, 300);
return true;
});
/* Add clear button to date fields */
$('input[type=date]').addClear();
})

View File

@ -1 +1,7 @@
{% extends "gadjo/base.html" %}
{% load staticfiles %}
{% block extrascripts %}
{{ block.super }}
<link href="{% static "css/bijoe.css" %}" rel="stylesheet">
{% endblock %}

View File

@ -2,136 +2,52 @@
{% load i18n staticfiles bijoe %}
{% block extrascripts %}
{% import_django_select2_js_css %}
{{ block.super }}
<script src="{% static "js/jquery.form.js" %}"></script>
<script src="{% static "js/addclear.js" %}"></script>
<script src="{% static "xstatic/ChartNew.js" %}"></script>
{{ form.media.css }}
{{ form.media.js }}
<style>
form p {
margin-bottom: 0.5ex;
}
form h3 {
margin-top: 0.5ex;
margin-bottom: 0.5ex;
}
.ui-datepicker select {
padding-right: 0px;
}
#id_filter__receipt_time_1 {
margin-left: 16px;
}
#data {
width: calc(100% - 23em);
}
#id_representation {
list-style: none;
padding: 0px;
text-align: justify;
display: flex;
justify-content: space-around;
}
#ods {
margin: 1ex;
top: -2ex;
}
form {
float: right;
width: 20em;
padding-left: 2em;
}
input[type=date] {
width: calc(100% / 2 - 8px);
}
select {
width: 100%;
}
td {
vertical-align: top;
}
#data td, #data th {
padding-left: 1ex;
padding-right: 1ex;
}
#data tbody td {
text-align: right;
}
#data tr:hover {
border: 3px solid grey;
}
tbody tr:nth-child(even) td:not([rowspan]) {
background: lightgrey;
}
#data table {
border-collapse: collapse;
line-height: 1.2em;
}
input[type=submit] {
float: right;
z-index: 1;
position: relative;
}
.filter { display: inline-block; }
th {
text-overflow: ellipsis;
text-align: left;
}
.download {
float: right;
bottom: -3em;
left: -2em;
position: relative;
background: #aaaaaa linear-gradient(to bottom, #f9f9f9, #eeeeee) repeat scroll 0 0;
border: 1px solid #b7b7b7;
border-radius: 1px;
box-shadow: 0 2px 2px 0 #ddd;
color: #424258;
cursor: pointer;
line-height: 100%;
padding: 1ex 2ex;
text-decoration: none;
}
</style>
<script>
function human_join(a) {
if (a.length == 0) {
return '';
}else if (a.length == 1) {
return a[0].toString();
} else {
return a.slice(0, -1).join(', ') + ' et ' + a.slice(-1)[0];
}
}
</script>
<style type="text/css" media="print">
/* hide UI */
#top, #header, #more-user-links, .download, #content form {
display: none;
}
/* resize content */
#data {
width: 100%;
}
</style>
{% import_django_select2_js_css %}
{{ block.super }}
<script src="{% static "js/jquery.form.js" %}"></script>
<script src="{% static "js/addclear.js" %}"></script>
<script src="{% static "xstatic/ChartNew.js" %}"></script>
<script src="{% static "js/bijoe.js" %}"></script>
{{ form.media.css }}
{{ form.media.js }}
{% endblock %}
{% block breadcrumb %}
{% url 'homepage' as homepage_url %}
{% url 'warehouse' warehouse=warehouse.name as warehouse_url %}
{% url 'homepage' as homepage_url %}
<a href="{{ homepage_url }}">{% trans "Homepage" %}</a>
<a href="{{ homepage_url }}">{% trans "Accueil" %}</a>
<a href="{{ warehouse_url }}">{{ warehouse.label }}</a>
<a>{{ cube.label }}</a>
{% url 'warehouse' warehouse=warehouse.name as warehouse_url %}
<a href="{{ warehouse_url }}">{{ warehouse.label }}</a>
<a>{{ cube.label }}</a>
{% if data %}
<a href="?{% firstof view.request.POST.urlencode view.request.GET.urlencode %}">
<span id="bijoe-slice-url-span">
{% for dim in drilldown %}
{% if not forloop.first %}
{% if forloop.last %}
{% trans "et" %}
{% else %}
,
{% endif %}
{% endif %}
{{ dim.label }}
{% endfor %}
par
{% for measure in measures %}
{% if not forloop.first %}
{% if forloop.last %}
{% trans "et" %}
{% else %}
,
{% endif %}
{% endif %}
{{ measure.label }}
{% endfor %}
</span>
</a>
{% endif %}
{% endblock %}
{% block content %}
@ -139,295 +55,28 @@ function human_join(a) {
{% csrf_token %}
<input type="submit" value="ODS" name="ods" id="ods"/>
<h3>Représentation</h3>
{% with field=form.representation %}
<p {% if field.css_classes %}class="{{ field.css_classes }}"{% endif %}>
{{ field }}
{% if field.help_text %}
<span class="helptext">{{ field.help_text }}</span>
{% endif %}
</p>
{% endwith %}
{% include "bijoe/field.html" with field=form.representation %}
<h3>Mesure(s)</h3>
{% with field=form.measures %}
<p {% if field.css_classes %}class="{{ field.css_classes }}"{% endif %}>
{{ field }}
{% if field.help_text %}
<span class="helptext">{{ field.help_text }}</span>
{% endif %}
</p>
{% endwith %}
{% include "bijoe/field.html" with field=form.measures %}
<h3>Regroupement(s)</h3>
{% with field=form.drilldown %}
<p {% if field.css_classes %}class="{{ field.css_classes }}"{% endif %}>
{{ field }}
{% if field.help_text %}
<span class="helptext">{{ field.help_text }}</span>
{% endif %}
</p>
{% endwith %}
{% include "bijoe/field.html" with field=form.drilldown %}
<h3>Filtre(s)</h3>
{% for field in form %}
{% if not field.is_hidden and field.name != "measures" and field.name != "drilldown" and field.name != "representation" %}
<p {% if field.css_classes %}class="{{ field.css_classes }}"{% endif %}>
{{ field.label_tag }}
{% if field.errors %}
<ul class="errorlist">
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{{ field }}
{% if field.help_text %}
<span class="helptext">{{ field.help_text }}</span>
{% endif %}
</p>
{% include "bijoe/filter_field.html" with field=field %}
{% endif %}
{% endfor %}
</form>
<div id="data">
{% if data %}
<a href="?{% firstof view.request.POST.urlencode view.request.GET.urlencode %}">URL</a>
{% if representation == 'table' %}
<table class="bijoe-table">
<thead>
{% for dimension in drilldown %}
<th><span>{{ dimension.label.capitalize }}</span></th>
{% endfor %}
{% for measure in measures %}
<th><span>{{ measure.label.capitalize }}</span></th>
{% endfor %}
</thead>
<tbody>
{% for row in grouped_data %}
<tr>
{% for cell, count in row %}
<td {% if count > 1 %}rowspan="{{ count }}"{% elif count == 0 %}class="measure"{% endif %}>{% if cell == None %}{% trans "None" %}{% else %}{{ cell }}{% endif %}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% include "bijoe/cube_table.html" %}
{% else %}
{% for measure in measures %}
<a href="#" download="graph.png" class="download">PNG</a>
<canvas style="width: 100%" id="canvas-{{ measure.name }}"></canvas>
<script>
function wrap_text(s, width) {
var words = s.split(" ");
var s = "";
var l = 0;
for (var i = 0; i < words.length; i++) {
l += 1 + words[i].length;
if (l > width) {
s = s + "\n";
l = words[i].length;
} else {
s = s + " ";
}
s = s + words[i];
}
return s;
}
var Colors = {};
Colors.spaced_hsla = function (i, n, s, l, a) {
var h = 360 * i/n;
return "hsla(" + h.toString() + ', ' + s.toString() + '%, ' + l.toString() + '%, ' + a.toString() + ')';
};
var data = {{ json|safe }};
var dataset = {data: [], title: "{{ measure.label }}", fillColor: [], strokeColor: [],
highlightFill: [], highlightStroke: []}
var linedata = {labels: [], datasets: [dataset]};
var dimensions = {{ drilldown_json|safe }};
var dimension_labels = [];
for (var i = 0; i < dimensions.length; i++) {
dimension_labels.push(dimensions[i].label);
}
for (var i = 0; i < data.length; i++) {
var row = data[i];
var label = [];
var datasets = linedata.datasets;
for (var j = 0; j < row.coords.length; j++) {
label.push(row.coords[j].value)
}
label = label.join(', ');
linedata.labels.push(label)
var n = data.length;
for (var j = 0; j < row.measures.length; j++) {
if (row.measures[j].label != "{{ measure.label }}") {
continue;
}
dataset.data.push(row.measures[j].value);
dataset.fillColor.push(Colors.spaced_hsla(i, n, 100, 30, 0.5));
dataset.strokeColor.push(Colors.spaced_hsla(i, n, 100, 30, 0.75));
dataset.highlightFill.push(Colors.spaced_hsla(i, n, 100, 30, 0.75));
dataset.highlightStroke.push(Colors.spaced_hsla(i, n, 100, 30, 1));
}
}
console.log("linedata", linedata);
var canvas = $('#canvas-{{ measure.name }}')[0];
var ctx = canvas.getContext("2d");
var option = {
animationSteps: 10,
//String - A legend template
responsive: true,
responseScaleContent: true,
legend: true,
dynamicDisplay: false,
yAxisMinimumInterval: 10,
inGraphDataShow: true,
legendFontColor: "rgb(0,0,0,1)",
scaleFontColor: "rgb(0,0,0,1)",
roundNumber: -2,
annotateDisplay : true,
datasetFill : true,
scaleLabel: "<%=value%>",
scaleFontSize : 16,
canvasBorders : true,
graphTitle : wrap_text("{{ measure.label|capfirst }}" + " par " + human_join(dimension_labels), 60),
graphTitleFontFamily : "'Arial'",
graphTitleFontSize : 24,
graphTitleFontStyle : "bold",
graphTitleFontColor : "#666",
legend : false,
}
if ("{{ measure.name }}".indexOf("delay") != -1) {
option.yAxisLabel = "jours";
}
if ("{{ measure.name }}" == "count") {
option.yAxisLabel = "quantité";
}
if ("{{ measure.name }}" == "percent") {
option.yAxisLabel = "pourcentage";
}
if ("{{ measure.name }}" == "percent") {
// pivot
var labels = linedata.labels;
linedata.labels = [""];
var datasets = [];
var empty = []
var Colors = {};
Colors.spaced_hsla = function (i, n, s, l, a) {
var h = 360 * i/n;
return "hsla(" + h.toString() + ', ' + s.toString() + '%, ' + l.toString() + '%, ' + a.toString() + ')';
}
var n = linedata.datasets[0].data.length;
for (var i = 0; i < n; i++) {
var value = linedata.datasets[0].data[i];
if (value > 1) {
dataset = {data: [value], title: labels[i] || "Aucun(e)"};
$.extend(dataset, {
fillColor: Colors.spaced_hsla(i, n, 100, 30, 0.5),
strokeColor: Colors.spaced_hsla(i, n, 100, 30, 0.75),
highlightFill: Colors.spaced_hsla(i, n, 100, 30, 0.75),
highlightStroke: Colors.spaced_hsla(i, n, 100, 30, 1)
})
datasets.push(dataset);
} else {
empty.push(labels[i]);
}
}
option.inGraphDataTmpl = "<%=v1+' '+v6+' %'%>";
option.annotateLabel = "<%=v1+' '+v6+' %'%>";
datasets.sort(function (a, b) { return a.value - b.value; });
if (empty.length) {
option.footNote = wrap_text("Les valeurs pour " + human_join(empty) + " sont nulles ou presque.", 110);
}
linedata.datasets = datasets;
console.log("pie data", linedata);
new Chart(ctx).Pie(linedata, option);
} else {
$.extend(option, {
//Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
scaleBeginAtZero : true,
//Boolean - Whether grid lines are shown across the chart
scaleShowGridLines : true,
//String - Colour of the grid lines
scaleGridLineColor : "rgba(0,0,0,.05)",
//Number - Width of the grid lines
scaleGridLineWidth : 1,
//Boolean - Whether to show horizontal lines (except X axis)
scaleShowHorizontalLines: true,
//Boolean - Whether to show vertical lines (except Y axis)
scaleShowVerticalLines: true,
//Boolean - If there is a stroke on each bar
// barShowStroke : true,
//Number - Pixel width of the bar stroke
barStrokeWidth : 2,
//Number - Spacing between each of the X value sets
barValueSpacing : 5,
//Number - Spacing between data sets within X values
barDatasetSpacing : 1,
});
new Chart(ctx).Bar(linedata, option);
}
console.log("option", option);
function toDataURL(canvas) {
destinationCanvas = document.createElement("canvas");
destinationCanvas.width = canvas.width;
destinationCanvas.height = canvas.height;
destCtx = destinationCanvas.getContext('2d');
//create a rectangle with the desired color
destCtx.fillStyle = "#FFFFFF";
destCtx.fillRect(0, 0, canvas.width, canvas.height);
//draw the original canvas onto the destination canvas
destCtx.drawImage(canvas, 0, 0);
var data = destinationCanvas.toDataURL("image/png");
data = data.split(";", 2)[1];
data = "data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=graph.png;" + data;
return data
}
$(".download").on('click', function() {
this.href = toDataURL($(this).next("canvas")[0]);
})
</script>
{% endfor %}
{% include "bijoe/cube_chart.html" %}
{% endif %}
{% else %}
<div class="big-msg-info">Veuillez choisir des mesures et des regroupements</div>
{% endif %}
</div>
<script>
$(function () {
$('input[type=date]').datepicker({
dateFormat: 'yy-mm-dd',
changeMonth: true,
changeYear: true,
},
$.datepicker.regional['fr']);
$('input, select').on('change', function () {
setTimeout(function () {
$('form').ajaxSubmit({success: function (data) {
var $content = $(data);
$('#data').empty();
$('#data').replaceWith($content.find('#data'));
}});
}, 800);
return true;
});
$('input[type=date]').addClear();
})
</script>
{% endblock %}
{% block page-end %}
<script>
{% if data %}
{% endif %}
</script>
{% endblock %}

View File

@ -0,0 +1,27 @@
<script>
var data = {{ json|safe }};
var dimensions = {{ drilldown_json|safe }};
var measures = {{ measures_json|safe }};
var dimension_labels = [];
for (var i = 0; i < dimensions.length; i++) {
dimension_labels.push(dimensions[i].label);
}
</script>
{% for measure in measures %}
<a href="#" target="none" class="bijoe-button bijoe-png-button">PNG</a>
<canvas id="canvas-{{ measure.name }}"></canvas>
<script>
var canvas = $('#canvas-{{ measure.name }}')[0];
if ("{{ measure.name }}" == "percent") {
draw_piechart(canvas, dimensions, measures, "{{ measure.name }}", data);
} else {
draw_barchart(canvas, dimensions, measures, "{{ measure.name }}", data);
/* Allow getting a PNG without using 'Save image as' */
$(".bijoe-png-button").on('click', function() {
this.href = toDataURL($(this).next("canvas")[0], "graph.png");
})
}
</script>
{% endfor %}

View File

@ -0,0 +1,21 @@
{% load i18n %}
<table class="bijoe-table">
<thead>
{% for dimension in drilldown %}
<th class="bijoe-drilldown"><span>{{ dimension.label.capitalize }}</span></th>
{% endfor %}
{% for measure in measures %}
<th class="bijoe-measure"><span>{{ measure.label.capitalize }}</span></th>
{% endfor %}
</thead>
<tbody>
{% for row in grouped_data %}
<tr>
{% for cell, count in row %}
<td {% if count > 1 %}rowspan="{{ count }}"{% endif %} {% if count > 0 %}class="bijoe-drilldown"{% elif count == 0 %}class="bijoe-measure"{% endif %}>{% if cell == None %}{% trans "Aucun(e)" %}{% else %}{{ cell }}{% endif %}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>

View File

@ -0,0 +1,6 @@
<p {% if field.css_classes %}class="{{ field.css_classes }}"{% endif %}>
{{ field }}
{% if field.help_text %}
<span class="helptext">{{ field.help_text }}</span>
{% endif %}
</p>

View File

@ -0,0 +1,14 @@
<p {% if field.css_classes %}class="{{ field.css_classes }}"{% endif %}>
{{ field.label_tag }}
{% if field.errors %}
<ul class="errorlist">
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{{ field }}
{% if field.help_text %}
<span class="helptext">{{ field.help_text }}</span>
{% endif %}
</p>