dataviz: add a gauge cell (#8477)
This commit is contained in:
parent
a2a1b66783
commit
5bde8c06ca
10
README
10
README
|
@ -126,3 +126,13 @@ details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License along
|
You should have received a copy of the GNU Affero General Public License along
|
||||||
with this program. If not, see <http://www.gnu.org/licenses/>.
|
with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
Combo embeds some other pieces of code, with their own authors and copyright
|
||||||
|
notices:
|
||||||
|
|
||||||
|
Gauge.js
|
||||||
|
Files: combo/apps/dataviz/static/js/gauge.min.js
|
||||||
|
License: MIT
|
||||||
|
Comment:
|
||||||
|
From http://bernii.github.io/gauge.js/
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# combo - content management system
|
||||||
|
# Copyright (C) 2015 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import django.apps
|
||||||
|
|
||||||
|
class AppConfig(django.apps.AppConfig):
|
||||||
|
name = 'combo.apps.dataviz'
|
||||||
|
|
||||||
|
def get_before_urls(self):
|
||||||
|
from . import urls
|
||||||
|
return urls.urlpatterns
|
||||||
|
|
||||||
|
default_app_config = 'combo.apps.dataviz.AppConfig'
|
|
@ -0,0 +1,36 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('auth', '0001_initial'),
|
||||||
|
('data', '0012_auto_20151029_1535'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Gauge',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('placeholder', models.CharField(max_length=20)),
|
||||||
|
('order', models.PositiveIntegerField()),
|
||||||
|
('slug', models.SlugField(verbose_name='Slug', blank=True)),
|
||||||
|
('public', models.BooleanField(default=True, verbose_name='Public')),
|
||||||
|
('restricted_to_unlogged', models.BooleanField(default=False, verbose_name='Restrict to unlogged users')),
|
||||||
|
('title', models.CharField(max_length=150, null=True, verbose_name='Title', blank=True)),
|
||||||
|
('url', models.URLField(max_length=150, null=True, verbose_name='URL', blank=True)),
|
||||||
|
('data_source', models.CharField(max_length=150, null=True, verbose_name='Data Source', blank=True)),
|
||||||
|
('max_value', models.PositiveIntegerField(null=True, verbose_name='Max Value', blank=True)),
|
||||||
|
('groups', models.ManyToManyField(to='auth.Group', verbose_name='Groups', blank=True)),
|
||||||
|
('page', models.ForeignKey(to='data.Page')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Gauge',
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('dataviz', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='gauge',
|
||||||
|
name='jsonp_data_source',
|
||||||
|
field=models.BooleanField(default=True, verbose_name='Use JSONP to get data'),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,57 @@
|
||||||
|
# combo - content management system
|
||||||
|
# Copyright (C) 2014-2015 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from combo.data.models import CellBase
|
||||||
|
from combo.data.library import register_cell_class
|
||||||
|
|
||||||
|
|
||||||
|
@register_cell_class
|
||||||
|
class Gauge(CellBase):
|
||||||
|
title = models.CharField(_('Title'), max_length=150, blank=True, null=True)
|
||||||
|
url = models.URLField(_('URL'), max_length=150, blank=True, null=True)
|
||||||
|
data_source = models.CharField(_('Data Source'), max_length=150,
|
||||||
|
blank=True, null=True)
|
||||||
|
jsonp_data_source = models.BooleanField(_('Use JSONP to get data'),
|
||||||
|
default=True)
|
||||||
|
max_value = models.PositiveIntegerField(_('Max Value'), blank=True, null=True)
|
||||||
|
|
||||||
|
template_name = 'combo/gauge-cell.html'
|
||||||
|
|
||||||
|
class Media:
|
||||||
|
js = ('js/gauge.min.js', 'js/combo.gauge.js')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('Gauge')
|
||||||
|
|
||||||
|
def get_additional_label(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
def get_cell_extra_context(self):
|
||||||
|
if self.jsonp_data_source:
|
||||||
|
data_source_url = self.data_source
|
||||||
|
else:
|
||||||
|
data_source_url = reverse('combo-ajax-gauge-count', kwargs={'cell': self.id})
|
||||||
|
return {'cell': self,
|
||||||
|
'title': self.title,
|
||||||
|
'url': self.url,
|
||||||
|
'max_value': self.max_value,
|
||||||
|
'data_source_url': data_source_url,
|
||||||
|
'jsonp': self.jsonp_data_source,
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
$(function() {
|
||||||
|
var opts = {
|
||||||
|
lines: 12, // The number of lines to draw
|
||||||
|
angle: 0.15, // The length of each line
|
||||||
|
lineWidth: 0.44, // The line thickness
|
||||||
|
pointer: {
|
||||||
|
length: 0.9, // The radius of the inner circle
|
||||||
|
strokeWidth: 0.035, // The rotation offset
|
||||||
|
color: '#000000' // Fill color
|
||||||
|
},
|
||||||
|
limitMax: 'false', // If true, the pointer will not go past the end of the gauge
|
||||||
|
colorStart: '#6FADCF', // Colors
|
||||||
|
colorStop: '#8FC0DA', // just experiment with them
|
||||||
|
strokeColor: '#E0E0E0', // to see which ones work best for you
|
||||||
|
percentColors: [[0.0, "#a9d70b" ], [0.8, "#f9c802"], [1.0, "#ff0000"]],
|
||||||
|
generateGradient: true
|
||||||
|
};
|
||||||
|
$('[data-combo-gauge').each(function(idx, elem) {
|
||||||
|
var target = $(elem).find('canvas')[0];
|
||||||
|
var gauge = new Gauge(target).setOptions(opts);
|
||||||
|
gauge.maxValue = parseInt($(elem).data('gauge-max-value'))
|
||||||
|
gauge.set(0); // set actual value
|
||||||
|
var ajax_params = {dataType: 'json'}
|
||||||
|
if ($(elem).data('gauge-count-url')) {
|
||||||
|
ajax_params.url = $(elem).data('gauge-count-url');
|
||||||
|
} else {
|
||||||
|
ajax_params.url = $(elem).data('gauge-count-jsonp-url');
|
||||||
|
ajax_params.xhrFields = { withCredentials: true };
|
||||||
|
ajax_params.crossDomain = true;
|
||||||
|
}
|
||||||
|
ajax_params.success = function(data) {
|
||||||
|
if (data.count > gauge.maxValue) {
|
||||||
|
gauge.animationSpeed = 16;
|
||||||
|
gauge.set(gauge.maxValue);
|
||||||
|
} else {
|
||||||
|
gauge.set(data.count);
|
||||||
|
}
|
||||||
|
var counter_value = $('<span class="counter">' + data.count + '</span>').appendTo(elem);
|
||||||
|
}
|
||||||
|
$.ajax(ajax_params);
|
||||||
|
});
|
||||||
|
});
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,14 @@
|
||||||
|
<div
|
||||||
|
data-combo-gauge="true"
|
||||||
|
{% if jsonp %}
|
||||||
|
data-gauge-count-jsonp-url="{{data_source_url}}"
|
||||||
|
{% else %}
|
||||||
|
data-gauge-count-url="{% url 'combo-ajax-gauge-count' cell=cell.id %}"
|
||||||
|
{% endif %}
|
||||||
|
data-gauge-max-value="{{max_value}}" class="bo-block">
|
||||||
|
<canvas style="width: 100%;">
|
||||||
|
</canvas>
|
||||||
|
{% if title %}
|
||||||
|
{% if url %}<a href="{{url}}">{% endif %}{{title}}{% if url %}</a>{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
|
@ -0,0 +1,24 @@
|
||||||
|
# combo - content management system
|
||||||
|
# Copyright (C) 2014-2015 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
|
from .views import ajax_gauge_count
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^ajax/gauge-count/(?P<cell>[\w_-]+)/$',
|
||||||
|
ajax_gauge_count, name='combo-ajax-gauge-count'),
|
||||||
|
)
|
|
@ -0,0 +1,29 @@
|
||||||
|
# combo - content management system
|
||||||
|
# Copyright (C) 2015 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.http import Http404, HttpResponse
|
||||||
|
|
||||||
|
from .models import Gauge
|
||||||
|
|
||||||
|
|
||||||
|
def ajax_gauge_count(request, *args, **kwargs):
|
||||||
|
gauge = Gauge.objects.get(id=kwargs['cell'])
|
||||||
|
response = requests.get(gauge.data_source)
|
||||||
|
return HttpResponse(response.content, content_type='text/json')
|
|
@ -18,3 +18,20 @@ div.welcome {
|
||||||
div.textcell {
|
div.textcell {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#content div.cell.gauge {
|
||||||
|
width: 270px;
|
||||||
|
max-width: 32%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.cell.gauge div.bo-block {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.cell.gauge div.bo-block span.counter {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 1ex;
|
||||||
|
font-size: 300%;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue