Projet

Général

Profil

0001-dataviz-add-a-gauge-cell-8477.patch

Frédéric Péters, 08 novembre 2015 15:41

Télécharger (27,2 ko)

Voir les différences:

Subject: [PATCH] dataviz: add a gauge cell (#8477)

 README                                             | 10 ++++
 combo/apps/dataviz/__init__.py                     | 26 ++++++++++
 combo/apps/dataviz/migrations/0001_initial.py      | 36 ++++++++++++++
 .../migrations/0002_gauge_jsonp_data_source.py     | 20 ++++++++
 combo/apps/dataviz/migrations/__init__.py          |  0
 combo/apps/dataviz/models.py                       | 57 ++++++++++++++++++++++
 combo/apps/dataviz/static/js/combo.gauge.js        | 42 ++++++++++++++++
 combo/apps/dataviz/static/js/gauge.min.js          |  1 +
 combo/apps/dataviz/templates/combo/gauge-cell.html | 14 ++++++
 combo/apps/dataviz/urls.py                         | 24 +++++++++
 combo/apps/dataviz/views.py                        | 29 +++++++++++
 data/themes/gadjo/static/css/agent-portal.css      | 17 +++++++
 12 files changed, 276 insertions(+)
 create mode 100644 combo/apps/dataviz/__init__.py
 create mode 100644 combo/apps/dataviz/migrations/0001_initial.py
 create mode 100644 combo/apps/dataviz/migrations/0002_gauge_jsonp_data_source.py
 create mode 100644 combo/apps/dataviz/migrations/__init__.py
 create mode 100644 combo/apps/dataviz/models.py
 create mode 100644 combo/apps/dataviz/static/js/combo.gauge.js
 create mode 100644 combo/apps/dataviz/static/js/gauge.min.js
 create mode 100644 combo/apps/dataviz/templates/combo/gauge-cell.html
 create mode 100644 combo/apps/dataviz/urls.py
 create mode 100644 combo/apps/dataviz/views.py
README
126 126

  
127 127
You should have received a copy of the GNU Affero General Public License along
128 128
with this program.  If not, see <http://www.gnu.org/licenses/>.
129

  
130

  
131
Combo embeds some other pieces of code, with their own authors and copyright
132
notices:
133

  
134
Gauge.js
135
  Files: combo/apps/dataviz/static/js/gauge.min.js
136
  License: MIT
137
  Comment:
138
   From http://bernii.github.io/gauge.js/
combo/apps/dataviz/__init__.py
1
# combo - content management system
2
# Copyright (C) 2015  Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
import django.apps
18

  
19
class AppConfig(django.apps.AppConfig):
20
    name = 'combo.apps.dataviz'
21

  
22
    def get_before_urls(self):
23
        from . import urls
24
        return urls.urlpatterns
25

  
26
default_app_config = 'combo.apps.dataviz.AppConfig'
combo/apps/dataviz/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import models, migrations
5

  
6

  
7
class Migration(migrations.Migration):
8

  
9
    dependencies = [
10
        ('auth', '0001_initial'),
11
        ('data', '0012_auto_20151029_1535'),
12
    ]
13

  
14
    operations = [
15
        migrations.CreateModel(
16
            name='Gauge',
17
            fields=[
18
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
19
                ('placeholder', models.CharField(max_length=20)),
20
                ('order', models.PositiveIntegerField()),
21
                ('slug', models.SlugField(verbose_name='Slug', blank=True)),
22
                ('public', models.BooleanField(default=True, verbose_name='Public')),
23
                ('restricted_to_unlogged', models.BooleanField(default=False, verbose_name='Restrict to unlogged users')),
24
                ('title', models.CharField(max_length=150, null=True, verbose_name='Title', blank=True)),
25
                ('url', models.URLField(max_length=150, null=True, verbose_name='URL', blank=True)),
26
                ('data_source', models.CharField(max_length=150, null=True, verbose_name='Data Source', blank=True)),
27
                ('max_value', models.PositiveIntegerField(null=True, verbose_name='Max Value', blank=True)),
28
                ('groups', models.ManyToManyField(to='auth.Group', verbose_name='Groups', blank=True)),
29
                ('page', models.ForeignKey(to='data.Page')),
30
            ],
31
            options={
32
                'verbose_name': 'Gauge',
33
            },
34
            bases=(models.Model,),
35
        ),
36
    ]
combo/apps/dataviz/migrations/0002_gauge_jsonp_data_source.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import models, migrations
5

  
6

  
7
class Migration(migrations.Migration):
8

  
9
    dependencies = [
10
        ('dataviz', '0001_initial'),
11
    ]
12

  
13
    operations = [
14
        migrations.AddField(
15
            model_name='gauge',
16
            name='jsonp_data_source',
17
            field=models.BooleanField(default=True, verbose_name='Use JSONP to get data'),
18
            preserve_default=True,
19
        ),
20
    ]
combo/apps/dataviz/models.py
1
# combo - content management system
2
# Copyright (C) 2014-2015  Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from django.core.urlresolvers import reverse
18
from django.db import models
19
from django.utils.translation import ugettext_lazy as _
20

  
21
from combo.data.models import CellBase
22
from combo.data.library import register_cell_class
23

  
24

  
25
@register_cell_class
26
class Gauge(CellBase):
27
    title = models.CharField(_('Title'), max_length=150, blank=True, null=True)
28
    url = models.URLField(_('URL'), max_length=150, blank=True, null=True)
29
    data_source = models.CharField(_('Data Source'), max_length=150,
30
            blank=True, null=True)
31
    jsonp_data_source = models.BooleanField(_('Use JSONP to get data'),
32
            default=True)
33
    max_value = models.PositiveIntegerField(_('Max Value'), blank=True, null=True)
34

  
35
    template_name = 'combo/gauge-cell.html'
36

  
37
    class Media:
38
        js = ('js/gauge.min.js', 'js/combo.gauge.js')
39

  
40
    class Meta:
41
        verbose_name = _('Gauge')
42

  
43
    def get_additional_label(self):
44
        return self.title
45

  
46
    def get_cell_extra_context(self):
47
        if self.jsonp_data_source:
48
            data_source_url = self.data_source
49
        else:
50
            data_source_url = reverse('combo-ajax-gauge-count', kwargs={'cell': self.id})
51
        return {'cell': self,
52
                'title': self.title,
53
                'url': self.url,
54
                'max_value': self.max_value,
55
                'data_source_url': data_source_url,
56
                'jsonp': self.jsonp_data_source,
57
                }
combo/apps/dataviz/static/js/combo.gauge.js
1
$(function() {
2
  var opts = {
3
    lines: 12, // The number of lines to draw
4
    angle: 0.15, // The length of each line
5
    lineWidth: 0.44, // The line thickness
6
    pointer: {
7
      length: 0.9, // The radius of the inner circle
8
      strokeWidth: 0.035, // The rotation offset
9
      color: '#000000' // Fill color
10
    },
11
    limitMax: 'false',   // If true, the pointer will not go past the end of the gauge
12
    colorStart: '#6FADCF',   // Colors
13
    colorStop: '#8FC0DA',    // just experiment with them
14
    strokeColor: '#E0E0E0',   // to see which ones work best for you
15
    percentColors: [[0.0, "#a9d70b" ], [0.8, "#f9c802"], [1.0, "#ff0000"]],
16
    generateGradient: true
17
  };
18
  $('[data-combo-gauge').each(function(idx, elem) {
19
    var target = $(elem).find('canvas')[0];
20
    var gauge = new Gauge(target).setOptions(opts);
21
    gauge.maxValue = parseInt($(elem).data('gauge-max-value'))
22
    gauge.set(0); // set actual value
23
    var ajax_params = {dataType: 'json'}
24
    if ($(elem).data('gauge-count-url')) {
25
      ajax_params.url = $(elem).data('gauge-count-url');
26
    } else {
27
      ajax_params.url = $(elem).data('gauge-count-jsonp-url');
28
      ajax_params.xhrFields = { withCredentials: true };
29
      ajax_params.crossDomain = true;
30
    }
31
    ajax_params.success = function(data) {
32
      if (data.count > gauge.maxValue) {
33
        gauge.animationSpeed = 16;
34
        gauge.set(gauge.maxValue);
35
      } else {
36
        gauge.set(data.count);
37
      }
38
      var counter_value = $('<span class="counter">' + data.count + '</span>').appendTo(elem);
39
    }
40
    $.ajax(ajax_params);
41
  });
42
});
combo/apps/dataviz/static/js/gauge.min.js
1
(function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q={}.hasOwnProperty,r=function(a,b){function c(){this.constructor=a}for(var d in b)q.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a};!function(){var a,b,c,d,e,f,g;for(g=["ms","moz","webkit","o"],c=0,e=g.length;e>c&&(f=g[c],!window.requestAnimationFrame);c++)window.requestAnimationFrame=window[f+"RequestAnimationFrame"],window.cancelAnimationFrame=window[f+"CancelAnimationFrame"]||window[f+"CancelRequestAnimationFrame"];return a=null,d=0,b={},requestAnimationFrame?window.cancelAnimationFrame?void 0:(a=window.requestAnimationFrame,window.requestAnimationFrame=function(c,e){var f;return f=++d,a(function(){return b[f]?void 0:c()},e),f},window.cancelAnimationFrame=function(a){return b[a]=!0}):(window.requestAnimationFrame=function(a,b){var c,d,e,f;return c=(new Date).getTime(),f=Math.max(0,16-(c-e)),d=window.setTimeout(function(){return a(c+f)},f),e=c+f,d},window.cancelAnimationFrame=function(a){return clearTimeout(a)})}(),String.prototype.hashCode=function(){var a,b,c,d,e;if(b=0,0===this.length)return b;for(c=d=0,e=this.length;e>=0?e>d:d>e;c=e>=0?++d:--d)a=this.charCodeAt(c),b=(b<<5)-b+a,b&=b;return b},o=function(a){var b,c;for(b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60),a-=3600*b+60*c,a+="",c+="";c.length<2;)c="0"+c;for(;a.length<2;)a="0"+a;return b=b?b+":":"",b+c+":"+a},m=function(a){return k(a.toFixed(0))},p=function(a,b){var c,d;for(c in b)q.call(b,c)&&(d=b[c],a[c]=d);return a},n=function(a,b){var c,d,e;d={};for(c in a)q.call(a,c)&&(e=a[c],d[c]=e);for(c in b)q.call(b,c)&&(e=b[c],d[c]=e);return d},k=function(a){var b,c,d,e;for(a+="",c=a.split("."),d=c[0],e="",c.length>1&&(e="."+c[1]),b=/(\d+)(\d{3})/;b.test(d);)d=d.replace(b,"$1,$2");return d+e},l=function(a){return"#"===a.charAt(0)?a.substring(1,7):a},j=function(){function a(a,b){null==a&&(a=!0),this.clear=null!=b?b:!0,a&&AnimationUpdater.add(this)}return a.prototype.animationSpeed=32,a.prototype.update=function(a){var b;return null==a&&(a=!1),a||this.displayedValue!==this.value?(this.ctx&&this.clear&&this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),b=this.value-this.displayedValue,Math.abs(b/this.animationSpeed)<=.001?this.displayedValue=this.value:this.displayedValue=this.displayedValue+b/this.animationSpeed,this.render(),!0):!1},a}(),e=function(a){function b(){return b.__super__.constructor.apply(this,arguments)}return r(b,a),b.prototype.displayScale=1,b.prototype.setTextField=function(a){return this.textField=a instanceof i?a:new i(a)},b.prototype.setMinValue=function(a,b){var c,d,e,f,g;if(this.minValue=a,null==b&&(b=!0),b){for(this.displayedValue=this.minValue,f=this.gp||[],g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(c.displayedValue=this.minValue);return g}},b.prototype.setOptions=function(a){return null==a&&(a=null),this.options=n(this.options,a),this.textField&&(this.textField.el.style.fontSize=a.fontSize+"px"),this.options.angle>.5&&(this.gauge.options.angle=.5),this.configDisplayScale(),this},b.prototype.configDisplayScale=function(){var a,b,c,d,e;return d=this.displayScale,this.options.highDpiSupport===!1?delete this.displayScale:(b=window.devicePixelRatio||1,a=this.ctx.webkitBackingStorePixelRatio||this.ctx.mozBackingStorePixelRatio||this.ctx.msBackingStorePixelRatio||this.ctx.oBackingStorePixelRatio||this.ctx.backingStorePixelRatio||1,this.displayScale=b/a),this.displayScale!==d&&(e=this.canvas.G__width||this.canvas.width,c=this.canvas.G__height||this.canvas.height,this.canvas.width=e*this.displayScale,this.canvas.height=c*this.displayScale,this.canvas.style.width=e+"px",this.canvas.style.height=c+"px",this.canvas.G__width=e,this.canvas.G__height=c),this},b}(j),i=function(){function a(a){this.el=a}return a.prototype.render=function(a){return this.el.innerHTML=m(a.displayedValue)},a}(),a=function(a){function b(a,b){this.elem=a,this.text=null!=b?b:!1,this.value=1*this.elem.innerHTML,this.text&&(this.value=0)}return r(b,a),b.prototype.displayedValue=0,b.prototype.value=0,b.prototype.setVal=function(a){return this.value=1*a},b.prototype.render=function(){var a;return a=this.text?o(this.displayedValue.toFixed(0)):k(m(this.displayedValue)),this.elem.innerHTML=a},b}(j),b={create:function(b){var c,d,e,f;for(f=[],d=0,e=b.length;e>d;d++)c=b[d],f.push(new a(c));return f}},h=function(a){function b(a){this.gauge=a,this.ctx=this.gauge.ctx,this.canvas=this.gauge.canvas,b.__super__.constructor.call(this,!1,!1),this.setOptions()}return r(b,a),b.prototype.displayedValue=0,b.prototype.value=0,b.prototype.options={strokeWidth:.035,length:.1,color:"#000000"},b.prototype.setOptions=function(a){return null==a&&(a=null),p(this.options,a),this.length=this.canvas.height*this.options.length,this.strokeWidth=this.canvas.height*this.options.strokeWidth,this.maxValue=this.gauge.maxValue,this.minValue=this.gauge.minValue,this.animationSpeed=this.gauge.animationSpeed,this.options.angle=this.gauge.options.angle},b.prototype.render=function(){var a,b,c,d,e,f,g,h,i;return a=this.gauge.getAngle.call(this,this.displayedValue),b=this.canvas.width/2,c=.9*this.canvas.height,h=Math.round(b+this.length*Math.cos(a)),i=Math.round(c+this.length*Math.sin(a)),f=Math.round(b+this.strokeWidth*Math.cos(a-Math.PI/2)),g=Math.round(c+this.strokeWidth*Math.sin(a-Math.PI/2)),d=Math.round(b+this.strokeWidth*Math.cos(a+Math.PI/2)),e=Math.round(c+this.strokeWidth*Math.sin(a+Math.PI/2)),this.ctx.fillStyle=this.options.color,this.ctx.beginPath(),this.ctx.arc(b,c,this.strokeWidth,0,2*Math.PI,!0),this.ctx.fill(),this.ctx.beginPath(),this.ctx.moveTo(f,g),this.ctx.lineTo(h,i),this.ctx.lineTo(d,e),this.ctx.fill()},b}(j),c=function(){function a(a){this.elem=a}return a.prototype.updateValues=function(a){return this.value=a[0],this.maxValue=a[1],this.avgValue=a[2],this.render()},a.prototype.render=function(){var a,b;return this.textField&&this.textField.text(m(this.value)),0===this.maxValue&&(this.maxValue=2*this.avgValue),b=this.value/this.maxValue*100,a=this.avgValue/this.maxValue*100,$(".bar-value",this.elem).css({width:b+"%"}),$(".typical-value",this.elem).css({width:a+"%"})},a}(),g=function(a){function b(a){this.canvas=a,b.__super__.constructor.call(this),this.percentColors=null,"undefined"!=typeof G_vmlCanvasManager&&(this.canvas=window.G_vmlCanvasManager.initElement(this.canvas)),this.ctx=this.canvas.getContext("2d"),this.gp=[new h(this)],this.setOptions(),this.render()}return r(b,a),b.prototype.elem=null,b.prototype.value=[20],b.prototype.maxValue=80,b.prototype.minValue=0,b.prototype.displayedAngle=0,b.prototype.displayedValue=0,b.prototype.lineWidth=40,b.prototype.paddingBottom=.1,b.prototype.percentColors=null,b.prototype.options={colorStart:"#6fadcf",colorStop:void 0,gradientType:0,strokeColor:"#e0e0e0",pointer:{length:.8,strokeWidth:.035},angle:.15,lineWidth:.44,fontSize:40,limitMax:!1},b.prototype.setOptions=function(a){var c,d,e,f;for(null==a&&(a=null),b.__super__.setOptions.call(this,a),this.configPercentColors(),this.lineWidth=this.canvas.height*(1-this.paddingBottom)*this.options.lineWidth,this.radius=this.canvas.height*(1-this.paddingBottom)-this.lineWidth,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.render(),f=this.gp,d=0,e=f.length;e>d;d++)c=f[d],c.setOptions(this.options.pointer),c.render();return this},b.prototype.configPercentColors=function(){var a,b,c,d,e,f,g;if(this.percentColors=null,void 0!==this.options.percentColors){for(this.percentColors=new Array,f=[],c=d=0,e=this.options.percentColors.length-1;e>=0?e>=d:d>=e;c=e>=0?++d:--d)g=parseInt(l(this.options.percentColors[c][1]).substring(0,2),16),b=parseInt(l(this.options.percentColors[c][1]).substring(2,4),16),a=parseInt(l(this.options.percentColors[c][1]).substring(4,6),16),f.push(this.percentColors[c]={pct:this.options.percentColors[c][0],color:{r:g,g:b,b:a}});return f}},b.prototype.set=function(a){var b,c,d,e,f,g,i;if(a instanceof Array||(a=[a]),a.length>this.gp.length)for(b=c=0,g=a.length-this.gp.length;g>=0?g>c:c>g;b=g>=0?++c:--c)this.gp.push(new h(this));for(b=0,f=!1,d=0,e=a.length;e>d;d++)i=a[d],i>this.maxValue&&(this.maxValue=1.1*this.value,f=!0),this.gp[b].value=i,this.gp[b++].setOptions({maxValue:this.maxValue,angle:this.options.angle});return this.value=a[a.length-1],f&&this.options.limitMax?void 0:AnimationUpdater.run()},b.prototype.getAngle=function(a){return(1+this.options.angle)*Math.PI+(a-this.minValue)/(this.maxValue-this.minValue)*(1-2*this.options.angle)*Math.PI},b.prototype.getColorForPercentage=function(a,b){var c,d,e,f,g,h,i;if(0===a)c=this.percentColors[0].color;else for(c=this.percentColors[this.percentColors.length-1].color,e=f=0,h=this.percentColors.length-1;h>=0?h>=f:f>=h;e=h>=0?++f:--f)if(a<=this.percentColors[e].pct){b===!0?(i=this.percentColors[e-1],d=this.percentColors[e],g=(a-i.pct)/(d.pct-i.pct),c={r:Math.floor(i.color.r*(1-g)+d.color.r*g),g:Math.floor(i.color.g*(1-g)+d.color.g*g),b:Math.floor(i.color.b*(1-g)+d.color.b*g)}):c=this.percentColors[e].color;break}return"rgb("+[c.r,c.g,c.b].join(",")+")"},b.prototype.getColorForValue=function(a,b){var c;return c=(a-this.minValue)/(this.maxValue-this.minValue),this.getColorForPercentage(c,b)},b.prototype.render=function(){var a,b,c,d,e,f,g,h,i;for(i=this.canvas.width/2,d=this.canvas.height*(1-this.paddingBottom),a=this.getAngle(this.displayedValue),this.textField&&this.textField.render(this),this.ctx.lineCap="butt",void 0!==this.options.customFillStyle?b=this.options.customFillStyle(this):null!==this.percentColors?b=this.getColorForValue(this.displayedValue,!0):void 0!==this.options.colorStop?(b=0===this.options.gradientType?this.ctx.createRadialGradient(i,d,9,i,d,70):this.ctx.createLinearGradient(0,0,i,0),b.addColorStop(0,this.options.colorStart),b.addColorStop(1,this.options.colorStop)):b=this.options.colorStart,this.ctx.strokeStyle=b,this.ctx.beginPath(),this.ctx.arc(i,d,this.radius,(1+this.options.angle)*Math.PI,a,!1),this.ctx.lineWidth=this.lineWidth,this.ctx.stroke(),this.ctx.strokeStyle=this.options.strokeColor,this.ctx.beginPath(),this.ctx.arc(i,d,this.radius,a,(2-this.options.angle)*Math.PI,!1),this.ctx.stroke(),g=this.gp,h=[],e=0,f=g.length;f>e;e++)c=g[e],h.push(c.update(!0));return h},b}(e),d=function(a){function b(a){this.canvas=a,b.__super__.constructor.call(this),"undefined"!=typeof G_vmlCanvasManager&&(this.canvas=window.G_vmlCanvasManager.initElement(this.canvas)),this.ctx=this.canvas.getContext("2d"),this.setOptions(),this.render()}return r(b,a),b.prototype.lineWidth=15,b.prototype.displayedValue=0,b.prototype.value=33,b.prototype.maxValue=80,b.prototype.minValue=0,b.prototype.options={lineWidth:.1,colorStart:"#6f6ea0",colorStop:"#c0c0db",strokeColor:"#eeeeee",shadowColor:"#d5d5d5",angle:.35},b.prototype.getAngle=function(a){return(1-this.options.angle)*Math.PI+(a-this.minValue)/(this.maxValue-this.minValue)*(2+this.options.angle-(1-this.options.angle))*Math.PI},b.prototype.setOptions=function(a){return null==a&&(a=null),b.__super__.setOptions.call(this,a),this.lineWidth=this.canvas.height*this.options.lineWidth,this.radius=this.canvas.height/2-this.lineWidth/2,this},b.prototype.set=function(a){return this.value=a,this.value>this.maxValue&&(this.maxValue=1.1*this.value),AnimationUpdater.run()},b.prototype.render=function(){var a,b,c,d,e,f;return a=this.getAngle(this.displayedValue),f=this.canvas.width/2,c=this.canvas.height/2,this.textField&&this.textField.render(this),b=this.ctx.createRadialGradient(f,c,39,f,c,70),b.addColorStop(0,this.options.colorStart),b.addColorStop(1,this.options.colorStop),d=this.radius-this.lineWidth/2,e=this.radius+this.lineWidth/2,this.ctx.strokeStyle=this.options.strokeColor,this.ctx.beginPath(),this.ctx.arc(f,c,this.radius,(1-this.options.angle)*Math.PI,(2+this.options.angle)*Math.PI,!1),this.ctx.lineWidth=this.lineWidth,this.ctx.lineCap="round",this.ctx.stroke(),this.ctx.strokeStyle=b,this.ctx.beginPath(),this.ctx.arc(f,c,this.radius,(1-this.options.angle)*Math.PI,a,!1),this.ctx.stroke()},b}(e),f=function(a){function b(){return b.__super__.constructor.apply(this,arguments)}return r(b,a),b.prototype.strokeGradient=function(a,b,c,d){var e;return e=this.ctx.createRadialGradient(a,b,c,a,b,d),e.addColorStop(0,this.options.shadowColor),e.addColorStop(.12,this.options._orgStrokeColor),e.addColorStop(.88,this.options._orgStrokeColor),e.addColorStop(1,this.options.shadowColor),e},b.prototype.setOptions=function(a){var c,d,e,f;return null==a&&(a=null),b.__super__.setOptions.call(this,a),f=this.canvas.width/2,c=this.canvas.height/2,d=this.radius-this.lineWidth/2,e=this.radius+this.lineWidth/2,this.options._orgStrokeColor=this.options.strokeColor,this.options.strokeColor=this.strokeGradient(f,c,d,e),this},b}(d),window.AnimationUpdater={elements:[],animId:null,addAll:function(a){var b,c,d,e;for(e=[],c=0,d=a.length;d>c;c++)b=a[c],e.push(AnimationUpdater.elements.push(b));return e},add:function(a){return AnimationUpdater.elements.push(a)},run:function(){var a,b,c,d,e;for(a=!0,e=AnimationUpdater.elements,c=0,d=e.length;d>c;c++)b=e[c],b.update()&&(a=!1);return a?cancelAnimationFrame(AnimationUpdater.animId):AnimationUpdater.animId=requestAnimationFrame(AnimationUpdater.run)}},"function"==typeof window.define&&null!=window.define.amd?define(function(){return{Gauge:g,Donut:f,BaseDonut:d,TextRenderer:i}}):"undefined"!=typeof module&&null!=module.exports?module.exports={Gauge:g,Donut:f,BaseDonut:d,TextRenderer:i}:(window.Gauge=g,window.Donut=f,window.BaseDonut=d,window.TextRenderer=i)}).call(this);
combo/apps/dataviz/templates/combo/gauge-cell.html
1
<div
2
     data-combo-gauge="true"
3
     {% if jsonp %}
4
        data-gauge-count-jsonp-url="{{data_source_url}}"
5
     {% else %}
6
        data-gauge-count-url="{% url 'combo-ajax-gauge-count' cell=cell.id %}"
7
     {% endif %}
8
     data-gauge-max-value="{{max_value}}" class="bo-block">
9
  <canvas style="width: 100%;">
10
  </canvas>
11
  {% if title %}
12
    {% if url %}<a href="{{url}}">{% endif %}{{title}}{% if url %}</a>{% endif %}
13
  {% endif %}
14
</div>
combo/apps/dataviz/urls.py
1
# combo - content management system
2
# Copyright (C) 2014-2015  Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from django.conf.urls import patterns, url
18

  
19
from .views import ajax_gauge_count
20

  
21
urlpatterns = patterns('',
22
    url(r'^ajax/gauge-count/(?P<cell>[\w_-]+)/$',
23
        ajax_gauge_count, name='combo-ajax-gauge-count'),
24
)
combo/apps/dataviz/views.py
1
# combo - content management system
2
# Copyright (C) 2015  Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
import json
18
import requests
19

  
20
from django.conf import settings
21
from django.http import Http404, HttpResponse
22

  
23
from .models import Gauge
24

  
25

  
26
def ajax_gauge_count(request, *args, **kwargs):
27
    gauge = Gauge.objects.get(id=kwargs['cell'])
28
    response = requests.get(gauge.data_source)
29
    return HttpResponse(response.content, content_type='text/json')
data/themes/gadjo/static/css/agent-portal.css
18 18
div.textcell {
19 19
	clear: both;
20 20
}
21

  
22
#content div.cell.gauge {
23
	width: 270px;
24
	max-width: 32%;
25
	float: left;
26
}
27

  
28
div.cell.gauge div.bo-block {
29
	position: relative;
30
}
31

  
32
div.cell.gauge div.bo-block span.counter {
33
	position: absolute;
34
	bottom: 0;
35
	right: 1ex;
36
	font-size: 300%;
37
}
21
-