Browse Source

[ADD] added module web_graph_radar

pull/328/head
Veronika 9 years ago
parent
commit
e5b9fd8083
  1. 4
      web_graph_radar/README.md
  2. 0
      web_graph_radar/__init__.py
  3. 35
      web_graph_radar/__openerp__.py
  4. 39
      web_graph_radar/i18n/ar.po
  5. 39
      web_graph_radar/i18n/de.po
  6. 38
      web_graph_radar/i18n/en.po
  7. 39
      web_graph_radar/i18n/es.po
  8. 39
      web_graph_radar/i18n/fi.po
  9. 39
      web_graph_radar/i18n/pt_BR.po
  10. 39
      web_graph_radar/i18n/sl.po
  11. 39
      web_graph_radar/i18n/tr.po
  12. BIN
      web_graph_radar/static/description/icon.png
  13. 885
      web_graph_radar/static/lib/nvd3-radar.js
  14. 86
      web_graph_radar/static/src/js/web_graph_radar.js
  15. 14
      web_graph_radar/static/src/xml/web_graph_radar.xml
  16. 20
      web_graph_radar/view/web_graph_radar.xml

4
web_graph_radar/README.md

@ -0,0 +1,4 @@
Graph Radar Chart.
=================
Add new graph view mode: Radar

0
web_graph_radar/__init__.py

35
web_graph_radar/__openerp__.py

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Veronika Kotovich @ IT-PROJECTS
# Copyright (C) 2016 Veronika Kotovich <veronika.kotovich@gmail.com>
#
# 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/>.
#
##############################################################################
{
'name': 'Radar Chart',
'version': '8.0.0.1.0',
'category': 'Web',
'summary': 'Add graph radar view.',
'author': "Veronika Kotovich,Odoo Community Association (OCA)",
'license': 'AGPL-3',
'website': 'https://twitter.com/vkotovi4',
'depends': ['web_graph'],
'qweb': ['static/src/xml/web_graph_radar.xml'],
'data': ['view/web_graph_radar.xml'],
'installable': True,
'auto_install': False,
}

39
web_graph_radar/i18n/ar.po

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_graph_improved
#
# Translators:
# SaFi J. <safi2266@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: web (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-12-16 07:41+0000\n"
"PO-Revision-Date: 2015-12-16 17:31+0000\n"
"Last-Translator: SaFi J. <safi2266@gmail.com>\n"
"Language-Team: Arabic (http://www.transifex.com/oca/OCA-web-8-0/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:13
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:14
#, python-format
msgid "Total"
msgstr "المجموع الاجمالي"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:30
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:40
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:44
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:49
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:54
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:57
#, python-format
msgid "Undefined"
msgstr "غير معرف"

39
web_graph_radar/i18n/de.po

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_graph_improved
#
# Translators:
# Rudolf Schnapka <rs@techno-flex.de>, 2016
msgid ""
msgstr ""
"Project-Id-Version: web (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-01-10 07:31+0000\n"
"PO-Revision-Date: 2016-01-18 20:15+0000\n"
"Last-Translator: Rudolf Schnapka <rs@techno-flex.de>\n"
"Language-Team: German (http://www.transifex.com/oca/OCA-web-8-0/language/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:13
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:14
#, python-format
msgid "Total"
msgstr "Gesamt"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:30
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:40
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:44
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:49
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:54
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:57
#, python-format
msgid "Undefined"
msgstr "Undefiniert"

38
web_graph_radar/i18n/en.po

@ -0,0 +1,38 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_graph_improved
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: web (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-23 13:46+0000\n"
"PO-Revision-Date: 2015-11-07 11:20+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>\n"
"Language-Team: English (http://www.transifex.com/oca/OCA-web-8-0/language/en/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: en\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:13
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:14
#, python-format
msgid "Total"
msgstr "Total"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:30
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:40
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:44
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:49
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:54
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:57
#, python-format
msgid "Undefined"
msgstr "Undefined"

39
web_graph_radar/i18n/es.po

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_graph_improved
#
# Translators:
# Pedro M. Baeza <pedro.baeza@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: web (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-23 13:46+0000\n"
"PO-Revision-Date: 2015-11-07 11:27+0000\n"
"Last-Translator: Pedro M. Baeza <pedro.baeza@gmail.com>\n"
"Language-Team: Spanish (http://www.transifex.com/oca/OCA-web-8-0/language/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:13
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:14
#, python-format
msgid "Total"
msgstr "Total"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:30
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:40
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:44
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:49
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:54
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:57
#, python-format
msgid "Undefined"
msgstr "Sin definir"

39
web_graph_radar/i18n/fi.po

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_graph_improved
#
# Translators:
# Jarmo Kortetjärvi <jarmo.kortetjarvi@gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: web (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-01-10 07:31+0000\n"
"PO-Revision-Date: 2016-02-01 09:54+0000\n"
"Last-Translator: Jarmo Kortetjärvi <jarmo.kortetjarvi@gmail.com>\n"
"Language-Team: Finnish (http://www.transifex.com/oca/OCA-web-8-0/language/fi/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: fi\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:13
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:14
#, python-format
msgid "Total"
msgstr "Yhteensä"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:30
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:40
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:44
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:49
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:54
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:57
#, python-format
msgid "Undefined"
msgstr "Ei määritelty"

39
web_graph_radar/i18n/pt_BR.po

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_graph_improved
#
# Translators:
# danimaribeiro <danimaribeiro@gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: web (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-03-11 02:17+0000\n"
"PO-Revision-Date: 2016-03-05 16:20+0000\n"
"Last-Translator: danimaribeiro <danimaribeiro@gmail.com>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/oca/OCA-web-8-0/language/pt_BR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: pt_BR\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:13
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:14
#, python-format
msgid "Total"
msgstr "Total"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:30
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:40
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:44
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:49
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:54
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:57
#, python-format
msgid "Undefined"
msgstr "Não definido"

39
web_graph_radar/i18n/sl.po

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_graph_improved
#
# Translators:
# Matjaž Mozetič <m.mozetic@matmoz.si>, 2015
msgid ""
msgstr ""
"Project-Id-Version: web (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-23 13:46+0000\n"
"PO-Revision-Date: 2015-11-08 05:45+0000\n"
"Last-Translator: Matjaž Mozetič <m.mozetic@matmoz.si>\n"
"Language-Team: Slovenian (http://www.transifex.com/oca/OCA-web-8-0/language/sl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: sl\n"
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:13
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:14
#, python-format
msgid "Total"
msgstr "Skupaj"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:30
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:40
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:44
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:49
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:54
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:57
#, python-format
msgid "Undefined"
msgstr "Nedoločeno"

39
web_graph_radar/i18n/tr.po

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_graph_improved
#
# Translators:
# Ahmet Altınışık <aaltinisik@altinkaya.com.tr>, 2015
msgid ""
msgstr ""
"Project-Id-Version: web (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-01-08 21:34+0000\n"
"PO-Revision-Date: 2015-12-30 22:16+0000\n"
"Last-Translator: Ahmet Altınışık <aaltinisik@altinkaya.com.tr>\n"
"Language-Team: Turkish (http://www.transifex.com/oca/OCA-web-8-0/language/tr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: tr\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:13
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:14
#, python-format
msgid "Total"
msgstr "Toplam"
#. module: web_graph_improved
#. openerp-web
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:30
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:40
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:44
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:49
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:54
#: code:addons/web_graph_improved/static/src/js/web_graph_improved.js:57
#, python-format
msgid "Undefined"
msgstr "Tanımsız"

BIN
web_graph_radar/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 9.2 KiB

885
web_graph_radar/static/lib/nvd3-radar.js

@ -0,0 +1,885 @@
nv.models.radar = function() {
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
var margin = {top: 0, right: 0, bottom: 0, left: 0}
, width = 500
, height = 500
, color = nv.utils.defaultColor() // a function that returns a color
, getValue = function(d) { return d.value } // accessor to get the x value from a data point
, size = 5
, scales = d3.scale.linear()
, radius
, max = 5
, startAngle = 0
, cursor = 0
, clipEdge = false
;
var line = d3.svg.line()
.x(function(d) { return d.x})
.y(function(d) { return d.y});
var scatter = nv.models.scatter()
.size(16) // default size
.sizeDomain([16,256])
;
//============================================================
//============================================================
// Private Variables
//------------------------------------------------------------
//============================================================
function chart(selection) {
selection.each(function(data) {
var availableWidth = width - margin.left - margin.right,
availableHeight = height - margin.top - margin.bottom,
container = d3.select(this)
;
// max = max || d3.max(data, getValue) > 0 ? d3.max(data, getValue) : 1
scales.domain([0, max]).range([0,radius]);
var current = 0;
if (cursor < 0) {
current = Math.abs(cursor);
}
else if (cursor > 0) {
current = size - cursor;
}
//------------------------------------------------------------
// Setup Scales
//compute proportions
var maxValue = 0;
for(var i=0; i<data.length; i++) {
var serie = data[i].values;
for(var j=0; j<serie.length; j++) {
if (serie[j].value > maxValue) {
maxValue = serie[j].value;
}
}
}
var factor = maxValue ? (radius-40)/maxValue/max/2 : 0;
data = data.map(function(serie, i) {
serie.values = serie.values.map(function(value, j) {
value.x = calculateX(value.value*factor, j, size);
value.y = calculateY(value.value*factor, j, size);
value.serie = i;
value.focus = (current == j) ? true : false;
return value;
});
return serie;
});
//------------------------------------------------------------
//------------------------------------------------------------
// Setup containers and skeleton of chart
var wrap = container.selectAll('g.nv-wrap.nv-radar').data([data]);
var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-radar');
var defsEnter = wrapEnter.append('defs');
var gEnter = wrapEnter.append('g');
var g = wrap.select('g')
gEnter.append('g').attr('class', 'nv-groups');
gEnter.append('g').attr('class', 'nv-scatterWrap');
// wrap.attr('transform', 'translate(' + radius + ',' + radius + ')');
//------------------------------------------------------------
// Points
scatter
.xScale(scales)
.yScale(scales)
.zScale(scales)
.color(color)
.useVoronoi(false)
.width(availableWidth)
.height(availableHeight);
var scatterWrap = wrap.select('.nv-scatterWrap');
//.datum(data); // Data automatically trickles down from the wrap
d3.transition(scatterWrap).call(scatter);
defsEnter.append('clipPath')
.attr('id', 'nv-edge-clip-' + scatter.id())
.append('rect');
wrap.select('#nv-edge-clip-' + scatter.id() + ' rect')
.attr('width', availableWidth)
.attr('height', availableHeight);
g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : '');
scatterWrap
.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : '');
// Series
var groups = wrap.select('.nv-groups').selectAll('.nv-group').data(function(d) { return d }, function(d) { return d.key });
groups.enter().append('g')
.style('stroke-opacity', 1e-6)
.style('fill-opacity', 1e-6);
d3.transition(groups.exit())
.style('stroke-opacity', 1e-6)
.style('fill-opacity', 1e-6)
.remove();
groups
.attr('class', function(d,i) { return 'nv-group nv-series-' + i })
.style('fill', function(d,i){ return color(d,i); })
.style('stroke', function(d,i){ return color(d,i); });
d3.transition(groups)
.style('stroke-opacity', 1)
.style('fill-opacity', .5);
var lineRadar = groups.selectAll('path.nv-line').data(function(d) { return [d.values] });
lineRadar.enter().append('path')
.attr('class', 'nv-line')
.attr('d', line );
d3.transition(lineRadar.exit())
.attr('d', line)
.remove();
lineRadar
.style('fill', function(d){ return color(d,d[0].serie); })
.style('stroke', function(d,i,j){ return color(d,d[0].serie); })
d3.transition(lineRadar)
.attr('d', line );
});
return chart;
}
// compute an angle
function angle(i, length) {
return i * (2 * Math.PI / length ) + ((2 * Math.PI) * startAngle / 360) + (cursor*2*Math.PI)/length;
}
// x-caclulator
// d is the datapoint, i is the index, length is the length of the data
function calculateX(d, i, length) {
var l = scales(d);
return Math.sin(angle(i, length)) * l;
}
// y-calculator
function calculateY(d, i, length) {
var l = scales(d);
return Math.cos(angle(i, length)) * l;
}
//============================================================
// Expose Public Variables
//------------------------------------------------------------
chart.dispatch = scatter.dispatch;
chart.scatter = scatter;
chart.margin = function(_) {
if (!arguments.length) return margin;
margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.size = function(_) {
if (!arguments.length) return size;
size = _;
return chart;
};
chart.scales = function(_) {
if (!arguments.length) return scales;
scales = _;
return chart;
};
chart.max = function(_) {
if (!arguments.length) return max;
max = _;
return chart;
};
chart.radius = function(_) {
if (!arguments.length) return radius;
radius = _;
return chart;
};
chart.color = function(_) {
if (!arguments.length) return color;
color = nv.utils.getColor(_);
return chart;
};
chart.startAngle = function(_) {
if (!arguments.length) return startAngle;
startAngle = _;
return chart;
};
chart.cursor = function(_) {
if (!arguments.length) return cursor;
cursor = _;
return chart;
};
//============================================================
return chart;
}
nv.models.radarChart = function() {
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
var radars = nv.models.radar()
, legend = nv.models.legend();
var margin = {top: 0, right: 0, bottom: 0, left: 0}
, color = nv.utils.defaultColor()
, width = null
, height = null
, showLegend = true
, legs = []
, ticks = 10 //Temp to test radar size issue
, scales = d3.scale.linear()
, edit = false
, radius
, startAngle = 180
, cursor = 0
, tooltips = true
, transitionDuration = 250
, tooltip = function(key, leg, value, e, graph) {
return '<h3>' + key + '</h3>' +
'<p>' + leg + ': ' + value + '</p>'
}
, dispatch = d3.dispatch('tooltipShow', 'tooltipHide','prevClick','stateChange')
;
var line = d3.svg.line()
.x(function(d) { return d.x})
.y(function(d) { return d.y});
//============================================================
//============================================================
// Private Variables
//------------------------------------------------------------
var showTooltip = function(e, offsetElement) {
// New addition to calculate position if SVG is scaled with viewBox, may move TODO: consider implementing everywhere else
if (offsetElement) {
var svg = d3.select(offsetElement).select('svg');
var viewBox = svg.attr('viewBox');
if (viewBox) {
viewBox = viewBox.split(' ');
var ratio = parseInt(svg.style('width')) / viewBox[2];
e.pos[0] = e.pos[0] * ratio;
e.pos[1] = e.pos[1] * ratio;
}
}
var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
top = e.pos[1] + ( offsetElement.offsetTop || 0),
val = e.series.values[e.pointIndex].value,
leg = legs[e.pointIndex].label,
content = tooltip(e.series.key, leg, val, e, chart);
nv.tooltip.show([left, top], content, null, null, offsetElement);
};
//============================================================
function chart(selection) {
selection.each(function(data) {
legs=data[0].values;//TODO: Think in a better way to put only the legs of the radar
var container = d3.select(this),
that = this,
size = legs.length,
availableWidth = (width || parseInt(container.style('width')) || 500) - margin.left - margin.right,
availableHeight = (height || parseInt(container.style('height')) || 500) - margin.top - margin.bottom;
chart.update = function() { container.transition().duration(transitionDuration).call(chart) };
chart.container = this;
var current = 0;
if (cursor < 0) {
current = Math.abs(cursor);
}
else if (cursor > 0) {
current = legs.length - cursor;
}
//------------------------------------------------------------
// Setup Scales
// scales = radars.scales();
radius = (availableWidth-300 >= availableHeight) ? (availableHeight)/2 : (availableWidth-300)/2;
scales.domain([0, ticks]).range([0,radius]);
//------------------------------------------------------------
//------------------------------------------------------------
// Setup containers and skeleton of chart
var wrap = container.selectAll('g.nv-wrap.nv-radarChart').data([data]);
var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-radarChart');
var gEnter = wrapEnter.append('g');
var g = wrap.select('g');
gEnter.append('g').attr('class', 'nv-controlWrap');
gEnter.append('g').attr('class', 'nv-gridWrap');
gEnter.append('g').attr('class', 'nv-radarsWrap');
gEnter.append('g').attr('class', 'nv-legendWrap');
var gridWrap = wrap.select('g.nv-gridWrap');
gridWrap.append("g").attr("class", "grid");
gridWrap.append("g").attr("class", "axes");
wrap.attr('transform', 'translate(' + parseFloat(radius + margin.left) + ',' + parseFloat(radius + margin.top) + ')');
//------------------------------------------------------------
//------------------------------------------------------------
// Legend
if (showLegend) {
legend.width(30);
g.select('.nv-legendWrap')
.datum(data)
.call(legend);
/*
if ( margin.top != legend.height()) {
margin.top = legend.height();
availableHeight = (height || parseInt(container.style('height')) || 400)
- margin.top - margin.bottom;
}
*/
g.select('.nv-legendWrap')
.attr('transform', 'translate(' + (radius + margin.left + margin.right) + ',' + (-radius) +')');
}
//------------------------------------------------------------
if (edit) {
startAngle = 135
//Focus
var currentLeg = legs[current];
var rgbLeg = hexToRgb("#000000");
var controlWrap = wrap.select('g.nv-controlWrap');
wrap.select('g.control').remove();
var controlEnter = controlWrap.append("g")
.attr("class", "control");
var controlLine = controlEnter.append("svg:line")
.attr('class', 'indicator')
.style("stroke", "#000000")
.style("fill", "none")
.style("opacity", 1)
.style("stroke-width", 1.5)
.attr("x1", Math.sin(angle(current, size)) * scales(scales.domain()[1]))
.attr("y1", Math.cos(angle(current, size)) * scales(scales.domain()[1]))
.attr("x2", Math.sin(angle(current, size)) * scales(scales.domain()[1]))
.attr("y2", Math.cos(angle(current, size)) * scales(scales.domain()[1]));
var controlDescription = controlEnter.append("svg:foreignObject")
.attr('width',200)
.attr('height',0)
.attr("x", Math.sin(angle(current, size)) * scales(scales.domain()[1]) * 2)
.attr("y", Math.cos(angle(current, size)) * scales(scales.domain()[1]));
controlDescription.append("xhtml:div")
.attr('class', 'radar-description')
.style("background-color", 'rgba('+rgbLeg.r+','+rgbLeg.g+','+rgbLeg.b+',0.1)')
.style('border-bottom', '1px solid '+"#000000")
.style("padding", "10px")
.style("text-align", "justify")
.text( currentLeg.description );
var controlActionContent = controlEnter.append("svg:foreignObject")
.attr('width',200)
.attr('height',50)
.attr("x", Math.sin(angle(current, size)) * scales(scales.domain()[1]) * 2)
.attr("y", Math.cos(angle(current, size)) * scales(scales.domain()[1]) - 25);
controlActionContent.append("xhtml:button")
.attr('type','button')
.attr('class','radar-prev btn btn-mini icon-arrow-left')
.text('prev');
var controlSelect = controlActionContent.append("xhtml:select")
.attr('class','radar-select-note');
controlSelect.append('xhtml:option')
.attr('value',0)
// .attr('selected', function(d,i){ return (d[0].values[current].value == 0) ? true : false;})
.text('Note')
controlSelect.append('xhtml:option')
.attr('value',1)
// .attr('selected', function(d,i){ return (d[0].values[current].value == 1) ? true : false;})
.text('Nul')
controlSelect.append('xhtml:option')
.attr('value',2)
//.attr('selected', function(d,i){ return (d[0].values[current].value == 2) ? true : false;})
.text('Mauvais')
controlSelect.append('xhtml:option')
.attr('value',3)
// .attr('selected', function(d,i){ return (d[0].values[current].value == 3) ? true : false;})
.text('Nul')
controlSelect.append('xhtml:option')
.attr('value',4)
// .attr('selected', function(d,i){ return (d[0].values[current].value == 4) ? true : false;})
.text('Bien')
controlSelect.append('xhtml:option')
.attr('value',5)
// .attr('selected', function(d,i){ return (d[0].values[current].value == 4) ? true : false;})
.text('Très bien')
controlActionContent.append("xhtml:button")
.attr('type','button')
.attr('class','radar-next btn btn-mini icon-arrow-right')
.text('next');
var checkOption = function (d) {
if(d[0].values[current].value == this.value){
return d3.select(this).attr("selected", "selected");
}
};
controlSelect.selectAll("option").each(checkOption);
// Animation
controlLine.transition().duration(500)
.attr("x1", Math.sin(angle(current, size)) * scales(scales.domain()[1]))
.attr("y1", Math.cos(angle(current, size)) * scales(scales.domain()[1]))
.attr("x2", Math.sin(angle(current, size)) * scales(scales.domain()[1]) * 2 + 200)
.attr("y2", Math.cos(angle(current, size)) * scales(scales.domain()[1]))
.each('end', function(d){ controlDescription.transition().duration(300).attr('height','100%') });
// Controls
controlWrap.select('.radar-prev')
.on('click', function(d) {
chart.prev();
selection.transition().call(chart);
});
controlWrap.select('.radar-next')
.on('click', function(d) {
chart.next();
selection.transition().call(chart);
});
controlWrap.select('.radar-select-note')
.on('change', function(d) {
d[0].values[current].value = this.value;
chart.next();
selection.transition().call(chart);
});
//change
} else {
cursor = 0;
startAngle = 180;
wrap.select('g.control').remove();
}
//------------------------------------------------------------
// Main Chart Component(s)
radars
.width(availableWidth)
.height(availableHeight)
.size(legs.length)
.max(ticks)
.startAngle(startAngle)
.cursor(cursor)
// .scales(scales)
.radius(radius)
.color(data.map(function(d,i) {
return d.color || color(d, i);
}).filter(function(d,i) { return !data[i].disabled }))
;
var radarWrap = g.select('.nv-radarsWrap')
.datum(data.filter(function(d) { return !d.disabled }));
d3.transition(radarWrap).call(radars);
//------------------------------------------------------------
//------------------------------------------------------------
// Setup Axes
// the grid data, number of ticks
var gridData = buildAxisGrid(size, ticks);
// Grid
var grid = wrap.select('.grid').selectAll('.gridlevel').data(gridData);
grid.exit().remove();
grid.enter().append("path")
.attr("class", "gridlevel")
.attr("d", line);
d3.transition(grid)
.attr('d', line );
grid.style("stroke", "#000")
.style("fill", "none")
.style("opacity", 0.3);
// Axes
var ax = wrap.select("g.axes").selectAll("g.axis").data(legs);
ax.exit().remove();
var axEnter = ax.enter().append("g")
.attr("class", "axis");
var legText = axEnter.append("svg:text")
.style("text-anchor", function(d, i) {
var x = Math.sin(angle(i, size)) * scales(scales.domain()[1]);
if (Math.abs(x) < 0.1) {
return "middle"
}
if (x > 0) {
return "start"
}
return "end"
})
.attr("dy", function(d, i) {
var y = Math.cos(angle(i, size)) * scales(scales.domain()[1]);
if (Math.abs(y) < 0.1) {
return ".72em"
}
if (y > 0) {
return "1em"
}
return "-.3em"
})
.style("fill", function(d){ return d.color; })
.style("font-size", "9pt")
.style("font-weight",function(d,i){ return (i == current && edit) ? "bold": "normal"; })
.style("opacity", function(d,i){ return (i == current && edit) ? 1: 0.4; })
.text(function(d){ return d.label})
.attr("x", function(d, i) { return Math.sin(angle(i, size)) * scales(scales.domain()[1]);})
.attr("y", function(d, i) { return Math.cos(angle(i, size)) * scales(scales.domain()[1]);})
;
legText.on('click', function(d,i) {
chart.cursor(legs.length - i);
selection.transition().call(chart);
});
d3.transition(ax)
.select("text")
.style("text-anchor", function(d, i) {
var x = Math.sin(angle(i, size)) * scales(scales.domain()[1]);
if (Math.abs(x) < 0.1) {
return "middle"
}
if (x > 0) {
return "start"
}
return "end"
})
.attr("dy", function(d, i) {
var y = Math.cos(angle(i, size)) * scales(scales.domain()[1]);
if (Math.abs(y) < 0.1) {
return ".72em"
}
if (y > 0) {
return "1em"
}
return "-.3em"
})
.style("font-weight",function(d,i){ return (i == current && edit) ? "bold": "normal"; })
.style("opacity", function(d,i){ return (i == current && edit) ? 1: 0.4; })
.attr("x", function(d, i) { return Math.sin(angle(i, size)) * scales(scales.domain()[1]);})
.attr("y", function(d, i) { return Math.cos(angle(i, size)) * scales(scales.domain()[1]);});
axEnter.append("svg:line")
.style("stroke", function(d){ return d.color; })
.style("fill", "none")
.style("stroke-width", 2)
.style("opacity", function(d,i){ return (i == current && edit) ? 1: 0.4; })
.attr("x1", function(d, i) { return Math.sin(angle(i, size)) * scales(scales.domain()[0]);})
.attr("y1", function(d, i) { return Math.cos(angle(i, size)) * scales(scales.domain()[0]);})
.attr("x2", function(d, i) { return Math.sin(angle(i, size)) * scales(scales.domain()[1]);})
.attr("y2", function(d, i) { return Math.cos(angle(i, size)) * scales(scales.domain()[1]);});
d3.transition(ax)
.select("line")
.style("opacity", function(d,i){ return (i == current && edit) ? 1: 0.4; })
.attr("x1", function(d, i) { return Math.sin(angle(i, size)) * scales(scales.domain()[0]);})
.attr("y1", function(d, i) { return Math.cos(angle(i, size)) * scales(scales.domain()[0]);})
.attr("x2", function(d, i) { return Math.sin(angle(i, size)) * scales(scales.domain()[1]);})
.attr("y2", function(d, i) { return Math.cos(angle(i, size)) * scales(scales.domain()[1]);});
//------------------------------------------------------------
//============================================================
// Event Handling/Dispatching (in chart's scope)
//------------------------------------------------------------
radars.dispatch.on('elementClick', function(d,i) {
chart.cursor(legs.length - d.pointIndex);
selection.transition().call(chart);
});
legend.dispatch.on('stateChange', function(newState) {
state = newState;
dispatch.stateChange(state);
chart.update();
});
/*legend.dispatch.on('legendClick', function(d,i) {
if (!d.disabled) return;
data = data.map(function(s) {
s.disabled = true;
return s;
});
d.disabled = false;
switch (d.key) {
case 'Grouped':
multibar.stacked(false);
break;
case 'Stacked':
multibar.stacked(true);
break;
}
state.stacked = multibar.stacked();
dispatch.stateChange(state);
chart.update();
});*/
/* legend.dispatch.on('legendClick', function(d,i) {
d.disabled = !d.disabled;
if (!data.filter(function(d) { return !d.disabled }).length) {
data.map(function(d) {
d.disabled = false;
wrap.selectAll('.nv-series').classed('disabled', false);
return d;
});
}
chart.update();
});*/
dispatch.on('tooltipShow', function(e) {
e.pos = [parseFloat(e.pos[0] + availableHeight/2 + margin.left), parseFloat(e.pos[1] + availableHeight/2 + margin.top)];
if (tooltips) showTooltip(e, that.parentNode);
});
//============================================================
});
return chart;
}
function hexToRgb(hex,opacity) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
// compute an angle
function angle(i, length) {
return i * (2 * Math.PI / length ) + ((2 * Math.PI) * startAngle / 360) + (cursor*2*Math.PI)/length;
}
// x-caclulator
// d is the datapoint, i is the index, length is the length of the data
function calculateX(d, i, length) {
var l = scales(d);
return Math.sin(angle(i, length)) * l;
}
// y-calculator
function calculateY(d, i, length) {
var l = scales(d);
return Math.cos(angle(i, length)) * l;
}
// * build the spider axis * //
// rewrite this to conform to d3 axis style? //
function buildAxisGrid(length, ticks) {
var min = scales.domain()[0];
var max = scales.domain()[1] > 0 ? scales.domain()[1] : 1;
var increase = max/ticks;
var gridData = []
for (var i = 0; i <= ticks; i++ ) {
var val = min + i*increase;
var d = [val];
var gridPoints = [];
for (var j = 0; j <= length; j++) {
gridPoints.push({
x: calculateX(d, j, length),
y: calculateY(d, j, length),
});
}
gridData.push(gridPoints)
}
return gridData;
}
//============================================================
// Event Handling/Dispatching (out of chart's scope)
//------------------------------------------------------------
radars.dispatch.on('elementMouseover.tooltip', function(e) {
dispatch.tooltipShow(e);
});
radars.dispatch.on('elementMouseout.tooltip', function(e) {
dispatch.tooltipHide(e);
});
dispatch.on('tooltipHide', function() {
if (tooltips) nv.tooltip.cleanup();
});
//============================================================
//============================================================
// Expose Public Variables
//------------------------------------------------------------
// expose chart's sub-components
chart.dispatch = dispatch;
chart.radars = radars;
chart.margin = function(_) {
if (!arguments.length) return margin;
margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.legs = function(_) {
if (!arguments.length) return legs;
legs = _;
return chart;
};
chart.showLegend = function(_) {
if (!arguments.length) return showLegend;
showLegend = _;
return chart;
};
chart.cursor = function(_) {
if (!arguments.length) return cursor;
cursor = _;
return chart;
};
chart.next = function(_) {
cursor = cursor - 1;
if (Math.abs(cursor) > legs.length-1) cursor = 0;
return chart;
};
chart.prev = function(_) {
cursor = cursor + 1;
if (cursor > legs.length-1) cursor = 0;
return chart;
};
chart.edit = function(_) {
if (!arguments.length) return edit;
edit = _;
return chart;
};
//============================================================
return chart;
}

86
web_graph_radar/static/src/js/web_graph_radar.js

@ -0,0 +1,86 @@
openerp.web_graph_radar = function(instance) {
var _t = instance.web._t;
instance.web_graph.Graph.include({
template: 'GraphWidgetRadar',
radar: function() {
var self = this,
dim_x = this.pivot.rows.groupby.length,
dim_y = this.pivot.cols.groupby.length,
data;
// No groupby
if ((dim_x === 0) && (dim_y === 0)) {
data = [{key: _t('Total'), values:[{
label: _t('Total'),
value: this.pivot.get_total()[0],
}]}];
// Only column groupbys
} else if ((dim_x === 0) && (dim_y >= 1)){
data = _.map(this.pivot.get_cols_with_depth(1), function (header) {
return {
key: header.title,
values: [{label:header.title, value: self.pivot.get_total(header)[0]}]
};
});
// Just 1 row groupby
} else if ((dim_x === 1) && (dim_y === 0)) {
data = _.map(self.pivot.measures, function(measure, i) {
var series = _.map(self.pivot.main_row().children, function (pt) {
var value = self.pivot.get_total(pt)[i],
title = (pt.title !== undefined) ? pt.title : _t('Undefined');
return {label: title, value: value};
});
return {key: self.pivot.measures[i].string, values:series};
});
// 1 row groupby and some col groupbys
} else if ((dim_x === 1) && (dim_y >= 1)) {
data = _.map(this.pivot.get_cols_with_depth(1), function (colhdr) {
var values = _.map(self.pivot.get_rows_with_depth(1), function (header) {
return {
label: header.title || _t('Undefined'),
value: self.pivot.get_values(header.id, colhdr.id)[0] || 0
};
});
return {key: colhdr.title || _t('Undefined'), values: values};
});
// At least two row groupby
} else {
var keys = _.uniq(_.map(this.pivot.get_rows_with_depth(2), function (hdr) {
return hdr.title || _t('Undefined');
}));
data = _.map(keys, function (key) {
var values = _.map(self.pivot.get_rows_with_depth(1), function (hdr) {
var subhdr = _.find(hdr.children, function (child) {
return ((child.title === key) || ((child.title === undefined) && (key === _t('Undefined'))));
});
return {
label: hdr.title || _t('Undefined'),
value: (subhdr) ? self.pivot.get_total(subhdr)[0] : 0
};
});
return {key:key, values: values};
});
}
console.log(data);
nv.addGraph(function () {
var chart = nv.models.radarChart();
// .stacked(self.bar_ui === 'stack')
// .showControls(show_controls);
chart.margin({left:200, top:20, bottom:20});
d3.select(self.svg)
.datum(data)
.attr('width', self.width)
.attr('height', self.height)
.call(chart);
// nv.utils.windowResize(chart.update);
return chart;
});
}
});
}

14
web_graph_radar/static/src/xml/web_graph_radar.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- vim:fdl=1:
-->
<templates id="template" xml:space="preserve">
<t t-name="GraphWidgetRadar" t-extend="GraphWidget">
<t t-jquery=".graph_mode_selection" t-operation="append">
<label class="btn btn-default" data-mode="radar" title="Radar Chart">
<input type="radio" name="modes"/><span class="fa fa-certificate"></span>
</label>
</t>
</t>
</templates>

20
web_graph_radar/view/web_graph_radar.xml

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="assets_backend"
name="web_graph_radar assets"
inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript"
src="/web_graph_radar/static/lib/nvd3-radar.js">
</script>
<script type="text/javascript"
src="/web_graph_radar/static/src/js/web_graph_radar.js">
</script>
</xpath>
</template>
</data>
</openerp>
Loading…
Cancel
Save