diff options
-rw-r--r-- | archaeological_files/forms.py | 8 | ||||
-rw-r--r-- | archaeological_files/models.py | 5 | ||||
-rw-r--r-- | ishtar_common/models.py | 45 | ||||
-rw-r--r-- | ishtar_common/static/media/style.css | 15 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/dashboards/dashboard_main.html | 3 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/dashboards/dashboard_main_detail.html | 88 | ||||
-rw-r--r-- | ishtar_common/templatetags/date_formating.py | 19 | ||||
-rw-r--r-- | ishtar_common/views.py | 11 |
8 files changed, 155 insertions, 39 deletions
diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index dbbbafbd9..68a004e4f 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -122,13 +122,15 @@ class FileFormSelection(forms.Form): raise forms.ValidationError(_(u"You should select a file.")) return cleaned_data -SLICING = (('year',_(u"years")), ("month",_(u"months"))) +SLICING = (("month",_(u"months")), ('year',_(u"years")),) DATE_SOURCE = (('creation',_(u"Creation date")), ("reception",_(u"Reception date"))) class DashboardForm(forms.Form): slicing = forms.ChoiceField(label=_("Slicing"), choices=SLICING, required=False) + department_detail = forms.BooleanField(label=_("Department detail"), + required=False) date_source = forms.ChoiceField(label=_("Date get from"), choices=DATE_SOURCE, required=False) file_type = forms.ChoiceField(label=_("File type"), choices=[], @@ -145,6 +147,10 @@ class DashboardForm(forms.Form): self.fields['saisine_type'].choices = models.SaisineType.get_types() self.fields['file_type'].choices = models.FileType.get_types() + def get_show_detail(self): + return hasattr(self, 'cleaned_data') and \ + self.cleaned_data.get('department_detail') + def get_date_source(self): date_source = 'creation' if hasattr(self, 'cleaned_data') and \ diff --git a/archaeological_files/models.py b/archaeological_files/models.py index 70570e145..a649ceac1 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -230,7 +230,7 @@ class File(BaseHistorizedItem, OwnPerms, ValueGetter, ShortMenuItem): return sorted(owns.all(), key=lambda x:x.cached_label) @classmethod - def get_periods(cls, slice='year', fltr={}, date_source='creation'): + def get_periods(cls, slice='month', fltr={}, date_source='creation'): date_var = date_source + '_date' q = cls.objects.filter(**{date_var+'__isnull':False}) if fltr: @@ -258,7 +258,8 @@ class File(BaseHistorizedItem, OwnPerms, ValueGetter, ShortMenuItem): q = cls.objects.filter(**{date_var+'__isnull':False}) if fltr: q = q.filter(**fltr) - return q.filter(**{date_var+'__year':year, date_var+'__month':month}) + q = q.filter(**{date_var+'__year':year, date_var+'__month':month}) + return q @classmethod def get_total_number(cls, fltr={}): diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 98f4addb7..c59f38674 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -561,10 +561,12 @@ class UserDashboard: .order_by('person__person_types') class Dashboard: - def __init__(self, model, slice='year', date_source=None, fltr={}): + def __init__(self, model, slice='year', date_source=None, show_detail=None, + fltr={}): # don't provide date_source if it is not relevant self.model = model self.total_number = model.get_total_number(fltr) + self.show_detail = show_detail history_model = self.model.history.model # last edited - created self.recents, self.lasts = [], [] @@ -597,21 +599,40 @@ class Dashboard: self.periods.sort() if not self.total_number or not self.periods: return + kwargs_num = base_kwargs.copy() + self.serie_labels = [_(u"Total")] # numbers if slice == 'year': - self.values = [('year', _(u"Year"), reversed(self.periods))] - self.numbers = [model.get_by_year(year, **base_kwargs).count() + self.values = [('year', "", + list(reversed(self.periods)))] + self.numbers = [model.get_by_year(year, **kwargs_num).count() for year in self.periods] - self.values += [('number', _(u"Number"), reversed(self.numbers))] + self.values += [('number', _(u"Number"), + list(reversed(self.numbers)))] if slice == 'month': - self.numbers = [model.get_by_month(*period, **base_kwargs).count() - for period in self.periods] - periods = reversed(self.periods) - self.periods = ["%d-%s-01" % (period[0], ('0'+str(period[1])) - if len(str(period[1])) == 1 else period[1]) - for period in periods] - self.values = [('month', _(u"Month"), self.periods)] - self.values += [('number', _(u"Number"), reversed(self.numbers))] + periods = list(reversed(self.periods)) + self.periods = ["%d-%s-01" % (p[0], ('0'+str(p[1])) + if len(str(p[1])) == 1 else p[1]) + for p in periods] + self.values = [('month', "", self.periods)] + if show_detail: + for dpt in settings.ISHTAR_DPTS: + self.serie_labels.append(unicode(dpt)) + idx = 'number_' + unicode(dpt) + kwargs_num['fltr'] = {"towns__numero_insee__startswith":\ + unicode(dpt)} + numbers = [model.get_by_month(*p.split('-')[:2], + **kwargs_num).count() + for p in self.periods] + self.values += [(idx, dpt, list(numbers))] + # put "Total" at the end + self.serie_labels.append(self.serie_labels.pop(0)) + kwargs_num['fltr'] = {} + self.numbers = [model.get_by_month(*p.split('-')[:2], + **kwargs_num).count() + for p in self.periods] + self.values += [('number', _(u"Total"), + list(self.numbers))] # calculate self.average = self.get_average() self.variance = self.get_variance() diff --git a/ishtar_common/static/media/style.css b/ishtar_common/static/media/style.css index 341308926..54a97ca77 100644 --- a/ishtar_common/static/media/style.css +++ b/ishtar_common/static/media/style.css @@ -669,6 +669,13 @@ table.confirm tr.spacer td:last-child{ padding:0.5em 1em; } +.chart-img{ + display:none; +} + +.chart-img-form{ + margin-top:1em; +} #window table th, .dashboard table.resume th{ background-color:#922; @@ -783,8 +790,7 @@ table.confirm tr.spacer td:last-child{ margin:0.3em; } -p.alert{ - color:#D14; +p.info-box, p.alert{ display:block; font-style:italic; width:670px; @@ -794,6 +800,11 @@ p.alert{ -moz-border-radius:8px; -webkit-border-radius:8px; border-radius:8px; + font-size: 0.9em; +} + +p.alert{ + color:#D14; background-image:url(images/red_flag.png); background-repeat:no-repeat; background-position:left center; diff --git a/ishtar_common/templates/ishtar/dashboards/dashboard_main.html b/ishtar_common/templates/ishtar/dashboards/dashboard_main.html index 8822875b5..868f8a5c3 100644 --- a/ishtar_common/templates/ishtar/dashboards/dashboard_main.html +++ b/ishtar_common/templates/ishtar/dashboards/dashboard_main.html @@ -6,9 +6,12 @@ <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/jqplot/jquery.jqplot.min.js"></script> <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/jqplot/plugins/jqplot.canvasTextRenderer.min.js"></script> <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/jqplot/plugins/jqplot.canvasAxisLabelRenderer.min.js"></script> +<script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/jqplot/plugins/jqplot.canvasAxisTickRenderer.min.js"></script> <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/jqplot/plugins/jqplot.highlighter.min.js"></script> <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/jqplot/plugins/jqplot.pieRenderer.min.js"></script> <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/jqplot/plugins/jqplot.dateAxisRenderer.min.js"></script> +<script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/jqplot/plugins/jqplot.cursor.min.js"></script> +<script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/jqplot/plugins/jqplot.cursor.min.js"></script> <link rel="stylesheet" href="{{STATIC_URL}}js/jqplot/jquery.jqplot.min.css" /> {% endblock %} {% block content %} diff --git a/ishtar_common/templates/ishtar/dashboards/dashboard_main_detail.html b/ishtar_common/templates/ishtar/dashboards/dashboard_main_detail.html index 610457ae3..820c50136 100644 --- a/ishtar_common/templates/ishtar/dashboards/dashboard_main_detail.html +++ b/ishtar_common/templates/ishtar/dashboards/dashboard_main_detail.html @@ -1,11 +1,8 @@ -{% load i18n %} +{% load i18n date_formating %} {% load url from future %} <div class='dashboard' id="{{unique_id}}-tab"> <div> <h4>{% trans "Numbers" %}</h4> - <p><strong>{% trans "Total:" %}</strong> {{dashboard.total_number}}</p> - <div class='table'> - <div id="chart_{{unique_id}}" style="height:400px; width:700px;"></div> {% if form %} <div class='form'> <form method='post' action="{% url 'dashboard-main-detail' item_name %}" id='{{unique_id}}_form'> @@ -16,15 +13,27 @@ </form> </div> {% endif %} - {% comment %} - <table> + <p><strong>{% trans "Total:" %}</strong> {{dashboard.total_number}}</p> + <div class='table'> + <div id="chart_{{unique_id}}" style="height:400px; width:700px;"></div> + <p class='info-box'>{% trans 'Draw rectangle on the graph to zoom. Double-click to reinitialize.' %}</p> + <div class='form chart-img-form'> + <button id="chart_img_display_{{unique_id}}" class='submit'>{% trans "Display as an image" %}</button> + <div id="chart_img_{{unique_id}}" class='chart-img'> + <div id="img_{{unique_id}}"></div> + <p class='info-box'>{% trans 'Right-click on this image to save it.' %}</p> + </div> + </div> + </div> + <div class='table'> + <table class='resume'> {% for idx, lbl, values in dashboard.values %} <tr class='idx {% if forloop.counter0|divisibleby:"2" %}even{%else%}odd{%endif%}'> <th>{{lbl}}</th> - {% for value in values %}<td>{{value}}</td>{% endfor%} + {% for value in values reversed %}{% if forloop.parentloop.counter0 %}<td>{% else %}<th>{%endif%}{{value|date_formating }}{% if forloop.parentloop.counter0 %}</td>{% else %}</th>{%endif%}{% endfor%} </tr> {% endfor%} - </table>{% endcomment %} + </table> </div> {% if dashboard.periods %} <h4>{% trans "By years" %}</h4> @@ -71,23 +80,41 @@ </div> <script language="javascript" type="text/javascript"> $(document).ready(function(){ -var values_{{unique_id}} = []; +{% for idx, lbl, values in dashboard.values %} {% if forloop.counter0 > 0 %} var values_{{forloop.counter0}}_{{unique_id}} = []; {% for idx, lbl, values in dashboard.values %} {% for value in values %} {% if forloop.parentloop.counter0 == 0 %} values_{{forloop.parentloop.parentloop.counter0}}_{{unique_id}}.push([{{VALUE_QUOTE|safe}}{{value}}{{VALUE_QUOTE|safe}}, 0]); {% elif forloop.parentloop.parentloop.counter0 == forloop.parentloop.counter0 %} values_{{forloop.parentloop.parentloop.counter0}}_{{unique_id}}[{{forloop.counter0}}][1] = {{value}}; {% endif %} {% endfor%} {% endfor%} {% endif %} {% endfor %} -{% for idx, lbl, values in dashboard.values %} {% for value in values %}{% ifequal forloop.parentloop.counter0 0 %} -values_{{unique_id}}.push([{{VALUE_QUOTE|safe}}{{value}}{{VALUE_QUOTE|safe}}, 0]); -{% else %}values_{{unique_id}}[{{forloop.counter0}}][1] = {{value}};{% endifequal %}{% endfor%}{% endfor%} +{% comment %} +# less compact version +{% for idx, lbl, values in dashboard.values %} + {% if forloop.counter0 > 0 %} + {% for idx, lbl, values in dashboard.values %} + {% for value in values %} + {% if forloop.parentloop.counter0 == 0 %} + values_{{forloop.parentloop.counter0}}_{{unique_id}}.push([{{VALUE_QUOTE|safe}}{{value}}{{VALUE_QUOTE|safe}}, 0]); + {% elif forloop.parentloop.counter0 == forloop.counter0 %} + values_{{forloop.counter0}}_{{unique_id}}[{{forloop.counter0}}][1] = {{value}}; + {% endif %} + {% endfor%} + {% endfor%} + {% endif %} +{% endfor %} +{% endcomment %} + + +if (typeof values_1_{{unique_id}} === 'undefined' + || values_1_{{unique_id}}.length == 0){ -if (values_{{unique_id}}.length > 0){ +$('#chart_img_{{unique_id}}').hide(); +$('#chart_{{unique_id}}').html("<p class='alert'>{% trans 'No data for theses criteria.' %}</p>"); +} else { var showmarker = false; -if (values_{{unique_id}}.length < 25){ +if (values_1_{{unique_id}}.length < 25){ var showmarker = true; } var plot_{{unique_id}} = $.jqplot('chart_{{unique_id}}', - [values_{{unique_id}}], { - series:[{showMarker:showmarker}], + [{% for idx, lbl, values in dashboard.values %}{% if forloop.counter0 > 0 %} {% if forloop.counter0 > 1 %}, {% endif%} values_{{forloop.counter0}}_{{unique_id}} {% endif %} {% endfor%}], { axes:{ {%ifequal slicing 'year'%} xaxis:{ label:'{% trans "Year" %}', @@ -98,7 +125,11 @@ var plot_{{unique_id}} = $.jqplot('chart_{{unique_id}}', xaxis:{ label:'{% trans "Month" %}', renderer:$.jqplot.DateAxisRenderer, - tickOptions:{formatString:'%b %Y'}, + tickRenderer:$.jqplot.CanvasAxisTickRenderer, + tickOptions:{ + formatString:'%b %Y', + angle:-25 + } },{%endifequal%} yaxis:{ label:'{% trans "Number"%}', @@ -108,11 +139,28 @@ var plot_{{unique_id}} = $.jqplot('chart_{{unique_id}}', highlighter: { show: true, sizeAdjust: 7.5 - } + }, + series:[{% for label in dashboard.serie_labels %} + {%if forloop.counter0%}, {% endif %}{label:"{{label}}"}{% endfor %} + ], + cursor:{ + show: true, + zoom:true, + showTooltip:false + }, + legend: { show:true, location: 'nw' } + }); + + $('#chart_img_display_{{unique_id}}').click(function(){ + $('#chart_img_{{unique_id}}').hide(); + $('#img_{{unique_id}}').html( + $('<img/>').attr( + 'src', $('#chart_{{unique_id}}').jqplotToImageStr({}) + ) + ); + $('#chart_img_{{unique_id}}').show('slow'); }); -} else { -$('#chart_{{unique_id}}').html("<p class='alert'>{% trans 'No data for theses criteria.' %}</p"); } $('#search_{{unique_id}}').click(function (){ diff --git a/ishtar_common/templatetags/date_formating.py b/ishtar_common/templatetags/date_formating.py new file mode 100644 index 000000000..eb81cf52c --- /dev/null +++ b/ishtar_common/templatetags/date_formating.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from datetime import datetime + +from django.template import Library +from django.utils.translation import ugettext as _ + +register = Library() + +@register.filter +def date_formating(value): + try: + d = datetime.strptime(unicode(value), '%Y-%m-%d') + return _(d.strftime("%B")).capitalize() + u" %d" % d.year + except ValueError: + # could be passed to non date value: on error return value + return value + diff --git a/ishtar_common/views.py b/ishtar_common/views.py index d20b8b2af..d15157eed 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -730,7 +730,11 @@ def dashboard_main_detail(request, item_name): 'ishtar/dashboards/dashboard_main_detail_users.html', dct, context_instance=RequestContext(request)) form = None - slicing, date_source, fltr = 'year', None, {} + slicing, date_source, fltr, show_detail = 'year', None, {}, False + if (item_name == 'files' and \ + 'archaeological_files' in settings.INSTALLED_APPS):\ + #or item_name == 'operations': + slicing = 'month' if item_name in DASHBOARD_FORMS: if request.method == 'POST': form = DASHBOARD_FORMS[item_name](request.POST) @@ -739,13 +743,16 @@ def dashboard_main_detail(request, item_name): fltr = form.get_filter() if hasattr(form, 'get_date_source'): date_source = form.get_date_source() + if hasattr(form, 'get_show_detail'): + show_detail = form.get_show_detail() else: form = DASHBOARD_FORMS[item_name]() lbl, dashboard = None, None if item_name == 'files' and \ 'archaeological_files' in settings.INSTALLED_APPS: from archaeological_files.models import File - dashboard_kwargs = {'slice':slicing, 'fltr':fltr,} + dashboard_kwargs = {'slice':slicing, 'fltr':fltr, + 'show_detail':show_detail} # date_source is only relevant when the form has set one if date_source: dashboard_kwargs['date_source'] = date_source |