improve cube view
* make it compatible with django-select2 >=5 by implemting a dummy templatetag * use jquery.form.js to submit cube settings * use addclear.js to clear data fields * make one chart by measure * use pie charts for percent measure * add automatic coloring of charts * use a button style for the Download PNG link of charts * add URL to bookmark cube settings
This commit is contained in:
parent
4d45677cf1
commit
69fb738818
|
@ -22,9 +22,15 @@ from django.utils.translation import ugettext as _
|
|||
|
||||
try:
|
||||
from django_select2.forms import Select2MultipleWidget
|
||||
|
||||
def build_select2_widget():
|
||||
return Select2MultipleWidget()
|
||||
except ImportError:
|
||||
from django_select2.widgets import Select2MultipleWidget
|
||||
|
||||
def build_select2_widget():
|
||||
return Select2MultipleWidget(select2_options={'width': 'resolve'})
|
||||
|
||||
|
||||
class DateRangeWidget(forms.MultiWidget):
|
||||
def __init__(self, attrs=None):
|
||||
|
@ -86,17 +92,17 @@ class CubeForm(forms.Form):
|
|||
label=dimension.label.capitalize(),
|
||||
choices=dimension.members,
|
||||
required=False,
|
||||
widget=Select2MultipleWidget(select2_options={'width': 'resolve'}))
|
||||
widget=build_select2_widget())
|
||||
|
||||
# group by
|
||||
choices = [(dimension.name, dimension.label) for dimension in cube.dimensions
|
||||
if dimension.type not in (datetime.datetime, datetime.date)]
|
||||
self.fields['drilldown'] = forms.MultipleChoiceField(
|
||||
label=_('Group by'), choices=choices, required=False,
|
||||
widget=Select2MultipleWidget(select2_options={'width': 'resolve'}))
|
||||
widget=build_select2_widget())
|
||||
|
||||
# measures
|
||||
choices = [(measure.name, measure.label) for measure in cube.measures]
|
||||
self.fields['measures'] = forms.MultipleChoiceField(
|
||||
label=_('Measures'), choices=choices,
|
||||
widget=Select2MultipleWidget(select2_options={'width': 'resolve'}))
|
||||
widget=build_select2_widget())
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/*!
|
||||
Author: Stephen Korecky
|
||||
Website: http://stephenkorecky.com
|
||||
Plugin Website: http://github.com/skorecky/Add-Clear
|
||||
Version: 2.0.6
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Stephen Korecky
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
;(function($, window, document, undefined) {
|
||||
|
||||
// Create the defaults once
|
||||
var pluginName = "addClear",
|
||||
defaults = {
|
||||
closeSymbol: "✖",
|
||||
color: "#CCC",
|
||||
top: 1,
|
||||
right: 4,
|
||||
returnFocus: false,
|
||||
showOnLoad: false,
|
||||
onClear: null,
|
||||
hideOnBlur: false,
|
||||
tabbable: true,
|
||||
paddingRight: '20px'
|
||||
};
|
||||
|
||||
// The actual plugin constructor
|
||||
function Plugin(element, options) {
|
||||
this.element = element;
|
||||
|
||||
this.options = $.extend({}, defaults, options);
|
||||
|
||||
this._defaults = defaults;
|
||||
this._name = pluginName;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
Plugin.prototype = {
|
||||
|
||||
init: function() {
|
||||
var $this = $(this.element),
|
||||
$clearButton,
|
||||
me = this,
|
||||
options = this.options;
|
||||
|
||||
$this.wrap("<span style='position:relative;' class='add-clear-span'></span>");
|
||||
var tabIndex = options.tabbable ? "" : " tabindex='-1'";
|
||||
$clearButton = $("<a href='#clear' style='display: none;'" + tabIndex + ">" + options.closeSymbol + "</a>");
|
||||
$this.after($clearButton);
|
||||
$this.next().css({
|
||||
color: options.color,
|
||||
'text-decoration': 'none',
|
||||
display: 'none',
|
||||
'line-height': 1,
|
||||
overflow: 'hidden',
|
||||
position: 'absolute',
|
||||
right: options.right,
|
||||
top: options.top
|
||||
}, this);
|
||||
|
||||
if (options.paddingRight) {
|
||||
$this.css({
|
||||
'padding-right': options.paddingRight
|
||||
});
|
||||
}
|
||||
|
||||
if ($this.val().length >= 1 && options.showOnLoad === true) {
|
||||
$clearButton.css({display: 'block'});
|
||||
}
|
||||
|
||||
$this.focus(function() {
|
||||
if ($(this).val().length >= 1) {
|
||||
$clearButton.css({display: 'block'});
|
||||
}
|
||||
});
|
||||
$this.change(function() {
|
||||
if ($(this).val().length >= 1) {
|
||||
$clearButton.css({display: 'block'});
|
||||
}
|
||||
});
|
||||
|
||||
$this.blur(function(e) {
|
||||
if (options.hideOnBlur) {
|
||||
setTimeout(function() {
|
||||
var relatedTarget = e.relatedTarget || e.explicitOriginalTarget || document.activeElement;
|
||||
if (relatedTarget !== $clearButton[0]) {
|
||||
$clearButton.css({display: 'none'});
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
var handleUserInput = function() {
|
||||
if ($(this).val().length >= 1) {
|
||||
$clearButton.css({display: 'block'});
|
||||
} else {
|
||||
$clearButton.css({display: 'none'});
|
||||
}
|
||||
};
|
||||
|
||||
var handleInput = function () {
|
||||
$this.off('keyup', handleUserInput);
|
||||
$this.off('cut', handleUserInput);
|
||||
handleInput = handleUserInput;
|
||||
handleUserInput.call(this);
|
||||
};
|
||||
|
||||
$this.on('keyup', handleUserInput);
|
||||
|
||||
$this.on('cut', function () {
|
||||
var self = this;
|
||||
setTimeout(function () {
|
||||
handleUserInput.call(self);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
$this.on('input', function () {
|
||||
handleInput.call(this);
|
||||
});
|
||||
|
||||
if (options.hideOnBlur) {
|
||||
$clearButton.blur(function () {
|
||||
$clearButton.css({display: 'none'});
|
||||
});
|
||||
}
|
||||
|
||||
$clearButton.click(function(e) {
|
||||
var $input = $(me.element);
|
||||
$input.val("");
|
||||
$(this).css({display: 'none'});
|
||||
if (options.returnFocus === true) {
|
||||
$input.focus();
|
||||
} else {
|
||||
$input.trigger('change');
|
||||
}
|
||||
if (options.onClear) {
|
||||
options.onClear($input);
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.fn[pluginName] = function(options) {
|
||||
return this.each(function() {
|
||||
if (!$.data(this, "plugin_" + pluginName)) {
|
||||
$.data(this, "plugin_" + pluginName,
|
||||
new Plugin(this, options));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
})(jQuery, window, document);
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,13 +1,14 @@
|
|||
{% extends "bijoe/base.html" %}
|
||||
{% load i18n staticfiles django_select2_tags %}
|
||||
{% load i18n staticfiles bijoe %}
|
||||
|
||||
{% block extrascripts %}
|
||||
{% import_django_select2_js_css %}
|
||||
{{ block.super }}
|
||||
{{ form.media.css }}
|
||||
<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;
|
||||
|
@ -30,7 +31,7 @@ form h3 {
|
|||
padding: 0px;
|
||||
text-align: justify;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
justify-content: space-around;
|
||||
}
|
||||
#ods {
|
||||
margin: 1ex;
|
||||
|
@ -73,29 +74,6 @@ tbody tr:nth-child(even) td:not([rowspan]) {
|
|||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
|
||||
/* table.bijoe-table {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
padding-left: 2em;
|
||||
width: 80%;
|
||||
height: 70vh;
|
||||
}
|
||||
table.bijoe-table thead {
|
||||
flex: 0 0 auto;
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
}
|
||||
table.bijoe-table tr {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
table.bijoe-table tbody {
|
||||
flex: 1 1 auto;
|
||||
display: block;
|
||||
overflow-y: auto;
|
||||
} */
|
||||
input[type=submit] {
|
||||
float: right;
|
||||
z-index: 1;
|
||||
|
@ -106,6 +84,42 @@ 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>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -151,7 +165,7 @@ th {
|
|||
{% endif %}
|
||||
</p>
|
||||
{% endwith %}
|
||||
<h3>Filtre(s)</h3
|
||||
<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 %}>
|
||||
|
@ -173,6 +187,7 @@ th {
|
|||
</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>
|
||||
|
@ -195,14 +210,39 @@ th {
|
|||
</table>
|
||||
{% else %}
|
||||
{% for measure in measures %}
|
||||
<h2>{{ measure.label }}</h2>
|
||||
<a href="#" download="graph.png" class="download">PNG</a>
|
||||
<canvas style="width: 100%" id="canvas-{{ measure.name }}"></canvas>
|
||||
<a href="#" download="graph.png" class="download">Download</a>
|
||||
<script>
|
||||
console.log('coucou');
|
||||
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: [], label: "{{ measure.label }}", axis: 1}
|
||||
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 = [];
|
||||
|
@ -210,20 +250,96 @@ for (var i = 0; i < data.length; i++) {
|
|||
for (var j = 0; j < row.coords.length; j++) {
|
||||
label.push(row.coords[j].value)
|
||||
}
|
||||
label = label.join(' ');
|
||||
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);
|
||||
var ctx = $('#canvas-{{ measure.name }}')[0].getContext("2d");
|
||||
ctx.fillStyle = '#FFFFFF';
|
||||
ctx.fillRect(0, 0, $('canvas')[0].width, $('canvas')[0].height);
|
||||
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,
|
||||
|
||||
|
@ -243,7 +359,7 @@ ctx.fillRect(0, 0, $('canvas')[0].width, $('canvas')[0].height);
|
|||
scaleShowVerticalLines: true,
|
||||
|
||||
//Boolean - If there is a stroke on each bar
|
||||
barShowStroke : true,
|
||||
// barShowStroke : true,
|
||||
|
||||
//Number - Pixel width of the bar stroke
|
||||
barStrokeWidth : 2,
|
||||
|
@ -253,39 +369,21 @@ ctx.fillRect(0, 0, $('canvas')[0].width, $('canvas')[0].height);
|
|||
|
||||
//Number - Spacing between data sets within X values
|
||||
barDatasetSpacing : 1,
|
||||
|
||||
//String - A legend template
|
||||
responsive: true,
|
||||
responsiveMinHeight: 300,
|
||||
legend: true,
|
||||
yAxisMinimumInterval: 10,
|
||||
inGraphDataShow: true,
|
||||
legendFontColor: "rgb(0,0,0,1)",
|
||||
scaleFontColor: "rgb(0,0,0,1)",
|
||||
roundNumber: -2,
|
||||
}
|
||||
if ("{{ measure.name }}".indexOf("delay") != -1) {
|
||||
option.yAxisLabel = "jours";
|
||||
});
|
||||
new Chart(ctx).Bar(linedata, option);
|
||||
}
|
||||
if ("{{ measure.name }}" == "count") {
|
||||
option.yAxisLabel = "quantité";
|
||||
}
|
||||
if ("{{ measure.name }}" == "percent") {
|
||||
option.yAxisLabel = "pourcentage";
|
||||
}
|
||||
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");
|
||||
|
@ -295,8 +393,7 @@ function toDataURL(canvas) {
|
|||
}
|
||||
|
||||
$(".download").on('click', function() {
|
||||
this.href = toDataURL($(this).prev("canvas")[0]);
|
||||
console.log(this.href);
|
||||
this.href = toDataURL($(this).next("canvas")[0]);
|
||||
})
|
||||
</script>
|
||||
{% endfor %}
|
||||
|
@ -317,6 +414,7 @@ $(function () {
|
|||
setTimeout(function () {
|
||||
$('form').ajaxSubmit({success: function (data) {
|
||||
var $content = $(data);
|
||||
$('#data').empty();
|
||||
$('#data').replaceWith($content.find('#data'));
|
||||
}});
|
||||
}, 800);
|
||||
|
@ -328,7 +426,6 @@ $(function () {
|
|||
{% endblock %}
|
||||
|
||||
{% block page-end %}
|
||||
{{ form.media.js }}
|
||||
<script>
|
||||
{% if data %}
|
||||
{% endif %}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
try:
|
||||
from django_select2.templatetags.django_select2_tags import *
|
||||
except ImportError:
|
||||
@register.simple_tag(name='import_django_select2_js_css')
|
||||
def import_all(light=0):
|
||||
return ''
|
||||
|
|
@ -19,7 +19,6 @@ import datetime
|
|||
import decimal
|
||||
import urllib
|
||||
from collections import OrderedDict
|
||||
import logging
|
||||
import hashlib
|
||||
|
||||
from django.shortcuts import resolve_url
|
||||
|
@ -170,6 +169,10 @@ class CubeView(AuthorizationMixin, CubeMixin, FormView):
|
|||
def get_form_kwargs(self):
|
||||
kwargs = super(CubeView, self).get_form_kwargs()
|
||||
kwargs['cube'] = self.cube
|
||||
if self.request.method == 'GET' and self.request.GET:
|
||||
kwargs.update({
|
||||
'data': self.request.GET,
|
||||
})
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
|
@ -205,9 +208,12 @@ class CubeView(AuthorizationMixin, CubeMixin, FormView):
|
|||
ctx['grouped_data'] = list(self.get_grouped_data(form.cleaned_data))
|
||||
ctx['measures'] = [self.cube.measures[measure] for measure in
|
||||
form.cleaned_data['measures']]
|
||||
ctx['measures_json'] = json.dumps([{'name': measure.name, 'label': measure.label} for measure in ctx['measures']])
|
||||
ctx['measures_json'] = json.dumps([
|
||||
{'name': measure.name, 'label': measure.label} for measure in ctx['measures']])
|
||||
ctx['drilldown'] = [self.cube.dimensions[dimension] for dimension in
|
||||
form.cleaned_data['drilldown']]
|
||||
ctx['drilldown_json'] = json.dumps([
|
||||
{'name': dim.name, 'label': dim.label} for dim in ctx['drilldown']])
|
||||
json_data = []
|
||||
for row in self.get_data(form.cleaned_data, stringify=False):
|
||||
coords = []
|
||||
|
|
Loading…
Reference in New Issue