Blame view

app/main/static/js/charges.js 13.3 KB
90c7b0e4   hitier   Small comments an...
1
2
function build_chart(div_selector, data_url, entity_name, category_type) {

5f89fdc7   hitier   Fix color scale: ...
3
    const main_elt = document.getElementById("main")
7c1b38be   hitier   Draw charts to fi...
4

5f89fdc7   hitier   Fix color scale: ...
5
6
7
    const margin = {top: 60, right: 350, bottom: 100, left: 90},
        width = main_elt.offsetWidth * 0.95 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;
54e2baa6   hitier   Add charge charts...
8

90c7b0e4   hitier   Small comments an...
9
    const height_ratio = 1.2;    // how murch room to give above chart for lisibility
ff5fd5bf   hitier   Less and Longer ...
10

5f89fdc7   hitier   Fix color scale: ...
11
12
    const tooltip_offset = {dx: 0, dy: 100}
    const tooltip_offset_dot = {dx: 20, dy: 60}
f9fef9d0   hitier   Add tooltip
13

90c7b0e4   hitier   Small comments an...
14
    const y_ticks_num = 5        // dont show to many y ticks for lisibility
f0706d95   hitier   Add color legend
15

90c7b0e4   hitier   Small comments an...
16
    const legend_cell_size = 15; // size of legend colored scare
5f89fdc7   hitier   Fix color scale: ...
17
    const legend_x = width + 20; // begin legend a bit after the end of the chart
54e2baa6   hitier   Add charge charts...
18

90c7b0e4   hitier   Small comments an...
19
    const dot_radius = 6;        // size of total line dot
f9c1f568   hitier   Add dot on total ...
20

5f89fdc7   hitier   Fix color scale: ...
21
22
    const xScale = d3.scaleBand()
        .range([0, width])
67ab2300   hitier   Fix appearance de...
23
        .padding(0.4);
6b44860d   hitier   Make a draw_line ...
24

5f89fdc7   hitier   Fix color scale: ...
25
    const yScale = d3.scaleLinear()
90c7b0e4   hitier   Small comments an...
26
        .range([height, 0]);
54e2baa6   hitier   Add charge charts...
27

90c7b0e4   hitier   Small comments an...
28
    var colorScale = d3.scaleOrdinal([]); //  Will be really set later by category type
de63cb72   hitier   Add title to proj...
29

90c7b0e4   hitier   Small comments an...
30
31
32
33

    //
    // Configure chart by the category given as arg
    //
83d933c9   hitier   New draw_categori...
34
35
    var chart_title = ""
    var category_title = ""
90c7b0e4   hitier   Small comments an...
36
37
    var draw_total_line = () => void 0;
    var draw_categories_bars = () => void 0;
7d095c38   hitier   One color scale b...
38

90c7b0e4   hitier   Small comments an...
39
    if (category_type == 'capacity') {
83d933c9   hitier   New draw_categori...
40
41
42
43
        chart_title = "Charges par fonction"
        category_title = "Fonction"
        //draw_total_line
        draw_categories_bars = draw_categories_grouped
7d095c38   hitier   One color scale b...
44
        colorScale = d3.scaleOrdinal(d3.schemeSet3);
90c7b0e4   hitier   Small comments an...
45
    } else if (category_type == 'service') {
83d933c9   hitier   New draw_categori...
46
47
48
49
        chart_title = "Charges par service"
        category_title = "Service"
        draw_total_line = draw_totalcharge_line
        draw_categories_bars = draw_categories_stacked
7d095c38   hitier   One color scale b...
50
        colorScale = d3.scaleOrdinal(d3.schemeTableau10);
90c7b0e4   hitier   Small comments an...
51
    } else if (category_type == 'project') {
c8b7caf5   hitier   Agent now uses co...
52
53
54
55
        chart_title = "Charges par projet"
        category_title = "Projet"
        draw_categories_bars = draw_categories_stacked
        colorScale = d3.scaleOrdinal(d3.schemeTableau10);
6b44860d   hitier   Make a draw_line ...
56
57
    } else {
        alert("ALERT ! Every body shall quit the boat, we are sinking ! ALERT !")
de63cb72   hitier   Add title to proj...
58
    }
54e2baa6   hitier   Add charge charts...
59
60
61
62
63
64
65
66

    const svg = d3.select(div_selector).append("svg")
        .attr("id", "svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

069a5102   hitier   Fixed tooltip
67
    const tooltip = d3.select('html')
f9fef9d0   hitier   Add tooltip
68
69
70
71
72
73
74
75
76
77
78
79
80
        .append("div")
        .style("opacity", 0)
        .attr("class", "tooltip")

    var mousemove = function (e, d) {
        tooltip
            .style("left", (e.pageX - tooltip_offset.dx) + "px")
            .style("top", (e.pageY - tooltip_offset.dy) + "px")
    }

    var mouseleave = function (d) {
        tooltip
            .transition()
67ab2300   hitier   Fix appearance de...
81
            .duration(900)
f9fef9d0   hitier   Add tooltip
82
83
84
85
86
87
            .style("opacity", 0)
    }

    var mouseover = function (e, d) {
        var category_name = d3.select(this.parentNode).datum().key
        var category_charge = d.data[category_name]
22397f43   hitier   Show tooltip on g...
88
89
90
91
92
93
94
95
96
        show_tooltip(e, category_name, category_charge)
    }

    var mouseovergrouped = function (e, d) {
        var category_name = d.key
        var category_charge = d.value
        show_tooltip(e, category_name, category_charge)
    }
    var show_tooltip = function (e, category_name, category_charge) {
f9fef9d0   hitier   Add tooltip
97
98
99
100
101
        tooltip
            .transition()
            .duration(200)
            .style("opacity", 1);
        tooltip
3c21ae9f   hitier   Change bar colors
102
            .html("<b>" + category_title + ":</b> " + category_name + "<br>" + "<b>Charge:</b> " + category_charge + "%")
f9fef9d0   hitier   Add tooltip
103
104
105
106
            .style("left", (e.pageX - tooltip_offset.dx) + "px")
            .style("top", (e.pageY - tooltip_offset.dy) + "px")
    }

f9c1f568   hitier   Add dot on total ...
107
108
109
110
111
112
    var mouseleavedot = function (e, d) {
        d3.select(this).transition()
            .duration(1)
            .attr("r", dot_radius);
        mouseleave(d);
    }
6b44860d   hitier   Make a draw_line ...
113

f9c1f568   hitier   Add dot on total ...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    var mouseoverdot = function (e, d) {
        d3.select(this).transition()
            .duration(1)
            .attr("r", dot_radius * 1.5);
        tooltip
            .transition()
            .duration(200)
            .style("opacity", 1)
        tooltip
            .html("<b>" + d.period + ": </b>" + d.total + "%")
            .style("left", (e.pageX - tooltip_offset_dot.dx) + "px")
            .style("top", (e.pageY - tooltip_offset_dot.dy) + "px")
    }

f0706d95   hitier   Add color legend
128
129
130
131
132
    var addlegend = function (color_scale) {

        let reverse_keys = color_scale.domain().reverse();

        let legend = svg.append('g')
ff5fd5bf   hitier   Less and Longer ...
133
            .attr('transform', 'translate(' + legend_x + ', -30)');
f0706d95   hitier   Add color legend
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

        legend.selectAll()
            .data(reverse_keys)
            .enter().append('rect')
            .attr('height', legend_cell_size + 'px')
            .attr('width', legend_cell_size + 'px')
            .attr('class', 'legend')
            .attr('x', 5)
            .attr('y', (d, i) => i * legend_cell_size)
            .style("fill", d => color_scale(d));

        legend.selectAll()
            .data(reverse_keys)
            .enter().append('text')
            .attr("transform", (d, i) => "translate(30, " + (i * legend_cell_size + legend_cell_size / 1.6) + ")")
            .attr('class', 'legend')
f0706d95   hitier   Add color legend
150
151
152
153
            .style("fill", "black")
            .text(d => d);
    }

83d933c9   hitier   New draw_categori...
154
155
    function draw_categories_grouped(data, categories) {

a07df204   hitier   Compute for group...
156
157
        var y_max = d3.max(data, function (d) {
            return d3.max(categories, function (c) {
a5294567   hitier   Rewrite anonymous...
158
                return +d[c]
a07df204   hitier   Compute for group...
159
160
161
162
            })
        });
        y_max = y_max * height_ratio
        yScale.domain([0, y_max])
83d933c9   hitier   New draw_categori...
163
164
165
166
        // Another scale for subgroup position
        var xCategories = d3.scaleBand()
            .domain(categories)
            .range([0, xScale.bandwidth()])
67ab2300   hitier   Fix appearance de...
167
            .padding([0.2])
83d933c9   hitier   New draw_categori...
168
169
170
171
172
173
174

        svg.append("g")
            .selectAll("g")
            // Enter in data = loop group per group
            .data(data)
            .enter()
            .append("g")
a5294567   hitier   Rewrite anonymous...
175
            .attr("transform", d => "translate(" + xScale(d.period) + ",0)")
83d933c9   hitier   New draw_categori...
176
177
178
179
180
181
182
            .selectAll("rect")
            .data(function (d) {
                return categories.map(function (key) {
                    return {key: key, value: d[key]};
                });
            })
            .enter().append("rect")
a5294567   hitier   Rewrite anonymous...
183
184
            .attr("x", d => xCategories(d.key))
            .attr("y", d => yScale(d.value))
83d933c9   hitier   New draw_categori...
185
            .attr("width", xCategories.bandwidth())
a5294567   hitier   Rewrite anonymous...
186
            .attr("height", d => height - yScale(d.value))
22397f43   hitier   Show tooltip on g...
187
            .attr("fill", d => colorScale(d.key))
ec07c812   hitier   Fix hover on grou...
188
            .attr("class", "bar")
22397f43   hitier   Show tooltip on g...
189
190
191
            .on("mouseover", mouseovergrouped)
            .on("mousemove", mousemove)
            .on("mouseleave", mouseleave);
83d933c9   hitier   New draw_categori...
192

a48677c4   hitier   Make a draw_categ...
193
194
    }

83d933c9   hitier   New draw_categori...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    function draw_categories_stacked(data, categories) {

        // Now build the stacked data for stacked bars
        //
        var stack = d3.stack()
            .keys(categories)
        // .order(d3.stackOrderNone)
        // .offset(d3.stackOffsetNone);
        var stacked_data = stack(data)

        // Get the max y to plot
        var y_max = d3.max(stacked_data[stacked_data.length - 1], d => d[1]);
        if (y_max == 0) {
            y_max = 100
        }
        // Enhance it by %ratio to leave room on the top of the graph
        y_max = y_max * height_ratio

        yScale.domain([0, y_max]);

90c7b0e4   hitier   Small comments an...
215
        // first draw one group for one category containing all bars over periods
a48677c4   hitier   Make a draw_categ...
216
217
218
219
        let groups = svg.selectAll("g.category")
            .data(stacked_data)
            .enter()
            .append("g")
83d933c9   hitier   New draw_categori...
220
            .style("fill", (d) => colorScale(d.key));
a48677c4   hitier   Make a draw_categ...
221

90c7b0e4   hitier   Small comments an...
222
        // then draw each period/category bar
a48677c4   hitier   Make a draw_categ...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
        let rect = groups.selectAll("rect")
            .data(d => d)
            .enter()
            .append("rect")
            .attr("class", "bar")
            .attr("x", d => xScale(d.data.period))
            .attr("width", xScale.bandwidth())
            // .attr("width", 5)
            .attr("y", d => yScale(d[1]))
            .attr("height", d => height - yScale(d[1] - d[0]))
            .on("mouseover", mouseover)
            .on("mousemove", mousemove)
            .on("mouseleave", mouseleave);

    }

6b44860d   hitier   Make a draw_line ...
239
240
    function draw_totalcharge_line(data) {
        // Build the total charge by period;
518c7cc5   hitier   Draw the total ca...
241
242
        // it will be used for the line drawing above bars.
        //
6b44860d   hitier   Make a draw_line ...
243
244
        var periods_total_charge = []

518c7cc5   hitier   Draw the total ca...
245
246
247
248
249
250
251
252
253
        data.forEach(function (d) {
            // get the list of values for all columns except the first one which is the period name
            var period_values = Object.values(d).slice(1)
            var row = {}
            row['period'] = d.period
            row['total'] = d3.sum(period_values)
            periods_total_charge.push(row)
        });

6b44860d   hitier   Make a draw_line ...
254
255
256
257
258
259
260
261
262
263
        // the line itselet
        //
        const line = d3.line()
            .x(d => (xScale.bandwidth() / 2) + xScale(d.period)) // décalage pour centrer au milieu des barres
            .y(d => yScale(d.total))
            .curve(d3.curveMonotoneX); // Fonction de courbe permettant de l'adoucir

        svg.append("path")
            .datum(periods_total_charge)
            .attr("class", "total-line")
83d933c9   hitier   New draw_categori...
264
265
            .attr("d", line)
            .lower();// set it below bars if called after
6b44860d   hitier   Make a draw_line ...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280

        // data dots at each point
        //
        svg.selectAll("line-circle")
            .data(periods_total_charge)
            .enter().append("circle")
            .attr("class", "total-circle")
            .attr("r", dot_radius)
            .attr("cx", function (d) {
                return (xScale.bandwidth() / 2) + xScale(d.period)
            })
            .attr("cy", function (d) {
                return yScale(d.total);
            })
            .on("mouseover", mouseoverdot)
83d933c9   hitier   New draw_categori...
281
282
            .on("mouseleave", mouseleavedot)
            .lower();// set it below bars if called after
6b44860d   hitier   Make a draw_line ...
283
284
285
286
287
        ;

    }

    d3.csv(data_url).then(data => {
a07df204   hitier   Compute for group...
288
        // we could get categories that way,
90c7b0e4   hitier   Small comments an...
289
        // but instead we want to filter by non zero, see later
6b44860d   hitier   Make a draw_line ...
290
        // var categories = data.columns.slice(1)
90c7b0e4   hitier   Small comments an...
291

6b44860d   hitier   Make a draw_line ...
292
293
294
        var periods = d3.map(data, d => d.period)
        xScale.domain(periods)

90c7b0e4   hitier   Small comments an...
295
296
        // Filter datas to only keep non zero categories
        // TODO: should be done on server (python/flask) side
518c7cc5   hitier   Draw the total ca...
297
        //
90c7b0e4   hitier   Small comments an...
298
        // 1- Get the charge sum for each category over periods
f0706d95   hitier   Add color legend
299
        // That will leave '0' to categories with no charge at all
a07df204   hitier   Compute for group...
300
        // TODO: to be done with Object.keys, Object.values and d3 filtering methods
ce5f45ea   hitier   Fix data bug
301
        //
6b44860d   hitier   Make a draw_line ...
302
        var categories_total_charge = {}
f0706d95   hitier   Add color legend
303
304
        data.forEach(function (d) {
            Object.keys(d).forEach(function (k) {
04f2b6e8   hitier   Fix period as cat...
305
306
307
                    if (k === 'period') {
                        return;
                    }
f0706d95   hitier   Add color legend
308
309
310
                    if (categories_total_charge.hasOwnProperty(k)) {
                        categories_total_charge[k] += +d[k]
                    } else {
ce5f45ea   hitier   Fix data bug
311
                        categories_total_charge[k] = d[k]
f0706d95   hitier   Add color legend
312
313
314
315
316
                    }
                }
            )
        })

518c7cc5   hitier   Draw the total ca...
317
        // 2- Now, filter only categories that have a non-zero charge
a07df204   hitier   Compute for group...
318
        // TODO: to be done with Object.keys, Object.values and d3 filtering methods
90c7b0e4   hitier   Small comments an...
319
        //
f0706d95   hitier   Add color legend
320
321
322
323
324
325
326
        var categories = []
        for (var key in categories_total_charge) {
            if (categories_total_charge[key] > 0) {
                categories.push(key)
            }
        }

518c7cc5   hitier   Draw the total ca...
327
        //
90c7b0e4   hitier   Small comments an...
328
        // Draw the  bars, stacked or grouped
83d933c9   hitier   New draw_categori...
329
330
        //
        draw_categories_bars(data, categories)
54e2baa6   hitier   Add charge charts...
331

518c7cc5   hitier   Draw the total ca...
332
        //
83d933c9   hitier   New draw_categori...
333
334
335
336
337
338
339
340
341
342
        //  Draw the total charge line ( may be)
        //
        draw_total_line(data, categories)

        //
        // This former list we use as color_scale domain.
        // And that allows us to build the legend
        //
        colorScale.domain(categories)
        addlegend(colorScale)
54e2baa6   hitier   Add charge charts...
343

f0706d95   hitier   Add color legend
344
345
        // Xaxis
        //
518c7cc5   hitier   Draw the total ca...
346
        const xAxis = d3.axisBottom(xScale)
f0706d95   hitier   Add color legend
347

f0706d95   hitier   Add color legend
348
        // Draw Xaxis
68fd83a8   hitier   Add axis
349
350
351
352
353
354
355
356
357
358
        svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis)
            .selectAll("text")
            .style("text-anchor", "end")
            .attr("dx", "-.9em")
            .attr("dy", ".15em")
            .attr("transform", "rotate(-65)");

90c7b0e4   hitier   Small comments an...
359
360
361
362
363
        // Yaxis
        //
        const yAxis = d3.axisLeft(yScale)
            .ticks(y_ticks_num)

f0706d95   hitier   Add color legend
364
        // Draw Yaxis
68fd83a8   hitier   Add axis
365
366
367
        svg.append("g")
            .attr("class", "y axis")
            .call(yAxis)
68fd83a8   hitier   Add axis
368

ff5fd5bf   hitier   Less and Longer ...
369
370
371
372
373
374
375
376
377
378
        // Draw horizontal lines
        svg.selectAll("y axis")
            .data(yScale.ticks(y_ticks_num))
            .enter()
            .append("line")
            .attr("class", d => (d == 0 ? "horizontalY0" : "horizontalY"))
            .attr("x1", 0)
            .attr("x2", width)
            .attr("y1", d => yScale(d))
            .attr("y2", d => yScale(d))
83d933c9   hitier   New draw_categori...
379
            .lower();// set it below bars if called after
ff5fd5bf   hitier   Less and Longer ...
380

f0706d95   hitier   Add color legend
381
        // Write Y axis title
68fd83a8   hitier   Add axis
382
383
384
385
386
        svg.append("text")
            .attr("text-anchor", "end")
            .attr("transform", "rotate(-90)")
            .attr("y", -margin.left + 40)
            .attr("x", -margin.top - 70)
83d933c9   hitier   New draw_categori...
387
            .text("Charge (% ETP)");
54e2baa6   hitier   Add charge charts...
388

6b44860d   hitier   Make a draw_line ...
389
        //
f0706d95   hitier   Add color legend
390
        // Write chart Title
6b44860d   hitier   Make a draw_line ...
391
392
        //

f0706d95   hitier   Add color legend
393
        // part 1
de63cb72   hitier   Add title to proj...
394
        svg.append("text")
3c21ae9f   hitier   Change bar colors
395
396
397
398
            .attr("x", (width / 2))
            .attr("y", 0 - (margin.top / 2) - 10)
            .attr("text-anchor", "middle")
            .style("font-size", "16px")
c8b7caf5   hitier   Agent now uses co...
399
            .text(entity_name);
f0706d95   hitier   Add color legend
400
        // part 2
de63cb72   hitier   Add title to proj...
401
        svg.append("text")
3c21ae9f   hitier   Change bar colors
402
403
404
405
406
            .attr("x", (width / 2))
            .attr("y", 0 - (margin.top / 2) + 10)
            .attr("text-anchor", "middle")
            .style("font-size", "12px")
            .text(chart_title);
54e2baa6   hitier   Add charge charts...
407

518c7cc5   hitier   Draw the total ca...
408

6b44860d   hitier   Make a draw_line ...
409
    }); // end of d3.csv().then({})
54e2baa6   hitier   Add charge charts...
410
411

}