cms/app-client/app/components/visu-langues.js
author Chloe Laisne <chloe.laisne@gmail.com>
Mon, 26 Sep 2016 19:52:44 +0200
changeset 295 e1f154f20f96
parent 294 f3dae62a0d8a
child 305 ff6cf3fc5f40
child 313 706f10bcdc3c
permissions -rw-r--r--
Add selected state to treemap

import Ember from 'ember';
import d3 from 'd3';
import ENV from 'app-client/config/environment';
import _ from 'lodash/lodash';

export default Ember.Component.extend({

    constants: Ember.inject.service(),
    filter: Ember.inject.service(),

    filterObserver: Ember.observer('filter.language', function() {
        Ember.$('.node').removeClass("selected");
        Ember.$('.node[data-id="' + this.get('filter').get('language') + '"]').addClass("selected");
    }),

    didInsertElement: function(){
        var self = this;
        var baseurl = ENV.rootURL.replace(/\/$/,"")+'/api/v1';

        d3.json(baseurl+"/languages", function(languages) {
            var margin = { top: 30, right: 0, bottom: 0, left: 0 };
            var width = $('#' + self.get('elementId')).width();
            var height = $('#' + self.get('elementId')).height() - margin.top - margin.bottom;

            var array = Object.keys(languages).map(function (key) { return languages[key]; });
            var oldMin = Math.min(...array),
                oldMax = Math.max(...array);
            var sum = array.reduce(function(a, b) { return a + b; });
            var average = sum / array.length;
            var newMin = Math.floor((average - oldMin)),
                newMax = Math.floor((oldMax - average));
            

            var x = d3.scale.linear()
                .domain([0, width])
                .range([0, width]),
                y = d3.scale.linear()
                .domain([0, height])
                .range([0, height]);

            var treemap = d3.layout.treemap()
                .children(function(d, depth) { return depth ? null : d._children; })
                .sort(function(a, b) { return a.value - b.value; })
                .value(function(d){
                    return Math.floor((((d.value - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin);
                })
                .round(false);

            var element = d3.select('#' + self.get('elementId'))
                .style("width", width + margin.left + margin.right + 'px')
                .style("height", height + margin.bottom + margin.top + 'px')
                .style("margin-left", -margin.left + "px")
                .style("margin-right", -margin.right + "px")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
                .style("shape-rendering", "crispEdges");

            var breadcrumbs = element.insert("div", ":first-child")
                .attr("class", "breadcrumbs")
                .attr("y", -margin.top)
                .style("width", width + 'px')
                .style("height", margin.top + 'px');

            var root = _.cloneDeep(self.constants.LANGUAGES_TREEMAP);
            root.x = root.y = 0;
            root.dx = width;
            root.dy = height;
            root.depth = 0;
            var transitioning = false;

            accumulate(root);
            layout(root);
            display(root);

            function accumulate(d) {
                d._children = d.children;
                if(d.children) {
                    d.value = d.children.reduce(function(p, v) { return p + accumulate(v); }, 0);
                } else {
                    d.value = languages[d.id] ? languages[d.id] : 0;
                }
                return d.value;
            }

            function layout(d) {
                if (d._children) {
                    treemap.nodes({_children: d._children});
                    d._children.forEach(function(c) {
                        function getCount(node, count = 0) {
                            var c = languages[node.id];
                            if(typeof c === 'undefined') {
                                node._children.forEach(function(child) {
                                    count = getCount(child, count);
                                });
                                return count;
                            } else {
                                return count + c;
                            }
                        }
                        c.count = getCount(c);
                        c.x = d.x + c.x * d.dx;
                        c.y = d.y + c.y * d.dy;
                        c.dx *= d.dx;
                        c.dy *= d.dy;
                        c.parent = d;
                        layout(c);
                    });
                }
            }

            function position() {
                return this.style("width", function(d) { return x(d.x + d.dx) - x(d.x) + 'px'; })
                    .style("height", function(d) { return y(d.y + d.dy) - y(d.y) + 'px'; })
                    .style("left", function(d) { return x(d.x) + 'px'; })
                    .style("top", function(d) { return y(d.y) + 'px'; });
            }

            function display(d) {
                breadcrumbs
                    .datum(d.parent)
                    .html(name(d))
                    .on("click", transition);

                var nodes = element.append("div")
                    .attr("class", "nodes")
                    .datum(d);

                var node = nodes.selectAll()
                    .data(d._children)
                    .enter()
                    .append("div")
                    .attr("data-id", function(d) { return d.id; });

                node.attr("class", function(d) { return "node" + ( d.id === self.get('filter').get('language') ? " selected" : "" ); })
                    .call(position)
                    .on("click", selectHandler);

                node.filter(function(d) { return d._children; })
                    .classed("children", true)
                    .on("click", transition)
                    .append("i")
                    .attr("class", "fa fa-folder-o");

                node.append("span")
                    .html(function(d) { return d.name + ' <span class="count">(' + d.count + ')</span>'; });

                function transition(d) {
                    if (transitioning || !d) {
                        return;
                    }

                    selectHandler(d);
                    transitioning = true;

                    var newNode = display(d),
                    transitionNodes = node.transition().duration(750),
                    transitionNewNodes = newNode.transition().duration(750);

                    x.domain([d.x, d.x + d.dx]);
                    y.domain([d.y, d.y + d.dy]);

                    element.style("shape-rendering", null);

                    element.selectAll(".node").sort(function(a, b) { return a.depth - b.depth; });

                    newNode.selectAll().style("fill-opacity", 0);

                    transitionNodes.style("opacity", 0)
                        .call(position);

                    transitionNewNodes.style("opacity", 1)
                        .call(position);

                    transitionNodes.remove().each("end", function() {
                        element.style("shape-rendering", "crispEdges");
                        transitioning = false;
                    });
                }

                function selectHandler (d){
                    if (d.id){
                        self.get('filter').set('language', d.id);
                    }
                }

                return node;
            }

            function name(d) {
                return d.parent ? name(d.parent) + '<span class="level">' + d.name + '</span>' : '<span class="root">' + d.name + '</span>';
            }

        });
    }

});