cms/app-client/app/components/visu-langues.js
changeset 188 d2cb39155997
parent 142 86fcf0c837c0
child 198 541e26eb356f
equal deleted inserted replaced
187:ca479ef64fb4 188:d2cb39155997
     2 import d3 from 'd3';
     2 import d3 from 'd3';
     3 import ENV from 'app-client/config/environment';
     3 import ENV from 'app-client/config/environment';
     4 import _ from 'lodash/lodash';
     4 import _ from 'lodash/lodash';
     5 
     5 
     6 export default Ember.Component.extend({
     6 export default Ember.Component.extend({
     7   constants: Ember.inject.service(),
     7 
     8   didInsertElement: function(){
     8     constants: Ember.inject.service(),
     9     var _this = this;
     9 
    10     var margin = {top: 20, right: 0, bottom: 0, left: 0},
    10     didInsertElement: function(){
       
    11         var self = this;
       
    12         var margin = {top: 20, right: 0, bottom: 0, left: 0},
    11         width = Ember.$("#chart_div").width(),
    13         width = Ember.$("#chart_div").width(),
    12         height = 600 - margin.top - margin.bottom,
    14         height = 600 - margin.top - margin.bottom,
    13         formatNumber = d3.format(",d"),
    15         formatNumber = d3.format(",d"),
    14         transitioning;
    16         transitioning;
    15 
    17 
    16     var x = d3.scale.linear()
    18         var x = d3.scale.linear()
    17         .domain([0, width])
    19             .domain([0, width])
    18         .range([0, width]);
    20             .range([0, width]);
    19 
    21 
    20     var y = d3.scale.linear()
    22         var y = d3.scale.linear()
    21         .domain([0, height])
    23             .domain([0, height])
    22         .range([0, height]);
    24             .range([0, height]);
    23 
    25 
    24     var treemap = d3.layout.treemap()
    26         var treemap = d3.layout.treemap()
    25         .children(function(d, depth) { return depth ? null : d._children; })
    27             .children(function(d, depth) { return depth ? null : d._children; })
    26         .sort(function(a, b) { return a.value - b.value; })
    28             .sort(function(a, b) { return a.value - b.value; })
    27         .ratio(height / width * 0.5 * (1 + Math.sqrt(5)))
    29             .ratio(height / width * 0.5 * (1 + Math.sqrt(5)))
    28         .round(false);
    30             .round(false);
    29 
    31 
    30     var svg = d3.select("#chart_div").append("svg")
    32         var svg = d3.select("#chart_div").append("svg")
    31         .attr("width", width + margin.left + margin.right)
    33             .attr("width", width + margin.left + margin.right)
    32         .attr("height", height + margin.bottom + margin.top)
    34             .attr("height", height + margin.bottom + margin.top)
    33         .style("margin-left", -margin.left + "px")
    35             .style("margin-left", -margin.left + "px")
    34         .style("margin.right", -margin.right + "px")
    36             .style("margin.right", -margin.right + "px")
    35       .append("g")
    37             .append("g")
    36         .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    38             .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    37         .style("shape-rendering", "crispEdges");
    39             .style("shape-rendering", "crispEdges");
    38 
    40 
    39     var grandparent = svg.append("g")
    41         var grandparent = svg.append("g")
    40         .attr("class", "grandparent");
    42             .attr("class", "grandparent");
    41 
    43 
    42     grandparent.append("rect")
    44         grandparent.append("rect")
    43         .attr("y", -margin.top)
    45             .attr("y", -margin.top)
    44         .attr("width", width)
    46             .attr("width", width)
    45         .attr("height", margin.top);
    47             .attr("height", margin.top);
    46 
    48 
    47     grandparent.append("text")
    49         grandparent.append("text")
    48         .attr("x", 6)
    50             .attr("x", 6)
    49         .attr("y", 6 - margin.top)
    51             .attr("y", 6 - margin.top)
    50         .attr("dy", ".75em");
    52             .attr("dy", ".75em");
    51 
    53 
    52     var baseurl = ENV.baseURL.replace(/\/$/,"")+'/api/v1';
    54         var baseurl = ENV.baseURL.replace(/\/$/,"")+'/api/v1';
    53     d3.json(baseurl+"/languages", function(languages) {
    55         d3.json(baseurl+"/languages", function(languages) {
    54 
    56 
    55       var root = _.cloneDeep(_this.constants.LANGUAGES_TREEMAP);
    57             var root = _.cloneDeep(self.constants.LANGUAGES_TREEMAP);
    56 
    58 
    57       initialize(root);
    59             initialize(root);
    58       accumulate(root);
    60             accumulate(root);
    59       layout(root);
    61             layout(root);
    60       display(root);
    62             display(root);
    61 
    63 
    62       function initialize(root) {
    64             function initialize(root) {
    63         root.x = root.y = 0;
    65                 root.x = root.y = 0;
    64         root.dx = width;
    66                 root.dx = width;
    65         root.dy = height;
    67                 root.dy = height;
    66         root.depth = 0;
    68                 root.depth = 0;
    67       }
    69             }
    68 
    70 
    69       // Aggregate the values for internal nodes. This is normally done by the
    71             // Aggregate the values for internal nodes. This is normally done by the
    70       // treemap layout, but not here because of our custom implementation.
    72             // treemap layout, but not here because of our custom implementation.
    71       // We also take a snapshot of the original children (_children) to avoid
    73             // We also take a snapshot of the original children (_children) to avoid
    72       // the children being overwritten when when layout is computed.
    74             // the children being overwritten when when layout is computed.
    73       function accumulate(d) {
    75             function accumulate(d) {
    74         d._children = d.children;
    76                 d._children = d.children;
    75         if(d.children) {
    77 
    76           d.value = d.children.reduce(function(p, v) { return p + accumulate(v); }, 0);
    78                 if(d.children) {
    77         } else if (_.isArray(d.id)) {
    79                     d.value = d.children.reduce(function(p, v) { return p + accumulate(v); }, 0);
    78           d.value = d.id.reduce(
    80                 } else if (_.isArray(d.id)) {
    79             function(s,lid) { return s + (languages[lid]?languages[lid]:0); },
    81                     d.value = d.id.reduce(function(s,lid) { return s + (languages[lid]?languages[lid]:0); }, 0);
    80             0
    82                 } else {
    81           );
    83                     d.value = languages[d.id]?languages[d.id]:0;
    82         }
    84                 }
    83         else {
    85 
    84           d.value = languages[d.id]?languages[d.id]:0;
    86                 return d.value;
    85         }
    87             }
    86         return d.value;
    88 
    87       }
    89             // Compute the treemap layout recursively such that each group of siblings
    88 
    90             // uses the same size (1×1) rather than the dimensions of the parent cell.
    89       // Compute the treemap layout recursively such that each group of siblings
    91             // This optimizes the layout for the current zoom state. Note that a wrapper
    90       // uses the same size (1×1) rather than the dimensions of the parent cell.
    92             // object is created for the parent node for each group of siblings so that
    91       // This optimizes the layout for the current zoom state. Note that a wrapper
    93             // the parent’s dimensions are not discarded as we recurse. Since each group
    92       // object is created for the parent node for each group of siblings so that
    94             // of sibling was laid out in 1×1, we must rescale to fit using absolute
    93       // the parent’s dimensions are not discarded as we recurse. Since each group
    95             // coordinates. This lets us use a viewport to zoom.
    94       // of sibling was laid out in 1×1, we must rescale to fit using absolute
    96             function layout(d) {
    95       // coordinates. This lets us use a viewport to zoom.
    97                 if (d._children) {
    96       function layout(d) {
    98                     treemap.nodes({_children: d._children});
    97         if (d._children) {
    99                     d._children.forEach(function(c) {
    98           treemap.nodes({_children: d._children});
   100                         c.x = d.x + c.x * d.dx;
    99           d._children.forEach(function(c) {
   101                         c.y = d.y + c.y * d.dy;
   100             c.x = d.x + c.x * d.dx;
   102                         c.dx *= d.dx;
   101             c.y = d.y + c.y * d.dy;
   103                         c.dy *= d.dy;
   102             c.dx *= d.dx;
   104                         c.parent = d;
   103             c.dy *= d.dy;
   105                         layout(c);
   104             c.parent = d;
   106                     });
   105             layout(c);
   107                 }
   106           });
   108             }
   107         }
   109 
   108       }
   110             function display(d) {
   109 
   111                 grandparent
   110       function display(d) {
   112                     .datum(d.parent)
   111         grandparent
   113                     .on("click", transition)
   112             .datum(d.parent)
   114                     .select("text")
   113             .on("click", transition)
   115                     .text(name(d));
   114             .select("text")
   116 
   115             .text(name(d));
   117                 var g1 = svg.insert("g", ".grandparent")
   116 
   118                     .datum(d)
   117         var g1 = svg.insert("g", ".grandparent")
   119                     .attr("class", "depth");
   118             .datum(d)
   120 
   119             .attr("class", "depth");
   121                 var g = g1.selectAll("g")
   120 
   122                     .data(d._children)
   121         var g = g1.selectAll("g")
   123                     .enter().append("g");
   122             .data(d._children)
   124 
   123             .enter().append("g");
   125                 g.classed("bla", true)
   124 
   126                     .on("click", selectHandler);
   125         g.classed("bla", true).on("click", selectHandler);
   127 
   126 
   128                 g.filter(function(d) { return d._children; })
   127         g.filter(function(d) { return d._children; })
   129                     .classed("children", true)
   128             .classed("children", true)
   130                     .on("click", transition);
   129             .on("click", transition);
   131 
   130 
   132                 g.append("rect")
   131         g.append("rect")
   133                     .attr("class", "parent")
   132             .attr("class", "parent")
   134                     .call(rect)
   133             // .attr("fill", (d.color || "#bbb"))
   135                     .append("title")
   134             .call(rect)
   136                     .text(function(d) { return formatNumber(d.value); });
   135           .append("title")
   137 
   136             .text(function(d) { return formatNumber(d.value); });
   138                 g.append("text")
   137 
   139                     .attr("dy", ".75em")
   138         g.append("text")
   140                     .text(function(d) { return d.name; })
   139             .attr("dy", ".75em")
   141                     .call(text);
   140             .text(function(d) { return d.name; })
   142 
   141             .call(text);
   143                 function transition(d) {
   142 
   144                     if (transitioning || !d) {
   143         function transition(d) {
   145                         return;
   144           if (transitioning || !d) { return; }
   146                     }
   145           selectHandler(d);
   147                     
   146           transitioning = true;
   148                     selectHandler(d);
   147 
   149                     transitioning = true;
   148           var g2 = display(d),
   150 
   149               t1 = g1.transition().duration(750),
   151                     var g2 = display(d),
   150               t2 = g2.transition().duration(750);
   152                     t1 = g1.transition().duration(750),
   151 
   153                     t2 = g2.transition().duration(750);
   152           // Update the domain only after entering new elements.
   154 
   153           x.domain([d.x, d.x + d.dx]);
   155                     // Update the domain only after entering new elements.
   154           y.domain([d.y, d.y + d.dy]);
   156                     x.domain([d.x, d.x + d.dx]);
   155 
   157                     y.domain([d.y, d.y + d.dy]);
   156           // Enable anti-aliasing during the transition.
   158 
   157           svg.style("shape-rendering", null);
   159                     // Enable anti-aliasing during the transition.
   158 
   160                     svg.style("shape-rendering", null);
   159           // Draw child nodes on top of parent nodes.
   161 
   160           svg.selectAll(".depth").sort(function(a, b) { return a.depth - b.depth; });
   162                     // Draw child nodes on top of parent nodes.
   161 
   163                     svg.selectAll(".depth").sort(function(a, b) { return a.depth - b.depth; });
   162           // Fade-in entering text.
   164 
   163           g2.selectAll("text").style("fill-opacity", 0);
   165                     // Fade-in entering text.
   164 
   166                     g2.selectAll("text").style("fill-opacity", 0);
   165           // Transition to the new view.
   167 
   166           t1.selectAll("text").call(text).style("fill-opacity", 0);
   168                     // Transition to the new view.
   167           t2.selectAll("text").call(text).style("fill-opacity", 1);
   169                     t1.selectAll("text").call(text).style("fill-opacity", 0);
   168           t1.selectAll("rect").call(rect);
   170                     t2.selectAll("text").call(text).style("fill-opacity", 1);
   169           t2.selectAll("rect").call(rect);
   171                     t1.selectAll("rect").call(rect);
   170 
   172                     t2.selectAll("rect").call(rect);
   171           // Remove the old node when the transition is finished.
   173 
   172           t1.remove().each("end", function() {
   174                     // Remove the old node when the transition is finished.
   173             svg.style("shape-rendering", "crispEdges");
   175                     t1.remove().each("end", function() {
   174             transitioning = false;
   176                         svg.style("shape-rendering", "crispEdges");
   175           });
   177                         transitioning = false;
   176         }
   178                     });
   177 
   179                 }
   178         function selectHandler (d){
   180 
   179           if (d.name === "Global"){
   181                 function selectHandler (d){
   180             return _this.sendAction('action', null);
   182                     if (d.id){
   181           }
   183                         self.get('setQueryParameters')(d.id);
   182           _this.sendAction('action', d.name);
   184                     }
   183         }
   185                 }
   184 
   186 
   185         return g;
   187                 return g;
   186       }
   188             }
   187 
   189 
   188       function text(text) {
   190             function text(text) {
   189         text.attr("x", function(d) { return x(d.x) + 6; })
   191                 text.attr("x", function(d) { return x(d.x) + 6; })
   190             .attr("y", function(d) { return y(d.y) + 6; });
   192                 .attr("y", function(d) { return y(d.y) + 6; });
   191       }
   193             }
   192 
   194 
   193       function rect(rect) {
   195             function rect(rect) {
   194         rect.attr("x", function(d) { return x(d.x); })
   196                 rect.attr("x", function(d) { return x(d.x); })
   195             .attr("y", function(d) { return y(d.y); })
   197                     .attr("y", function(d) { return y(d.y); })
   196             .attr("width", function(d) { return x(d.x + d.dx) - x(d.x); })
   198                     .attr("width", function(d) { return x(d.x + d.dx) - x(d.x); })
   197             .attr("height", function(d) { return y(d.y + d.dy) - y(d.y); })
   199                     .attr("height", function(d) { return y(d.y + d.dy) - y(d.y); })
   198             .attr("fill", function(d) { return (d.color || "#bbb"); });
   200                     .attr("fill", function(d) { return (d.color || "#bbb"); });
   199       }
   201             }
   200 
   202 
   201       function name(d) {
   203             function name(d) {
   202         return d.parent ? name(d.parent) + "." + d.name : d.name;
   204                 return d.parent ? name(d.parent) + "." + d.name : d.name;
   203       }
   205             }
   204     });
   206 
   205   }
   207         });
       
   208 
       
   209     }
       
   210 
   206 });
   211 });