Commit 22c5ff6001e904dc39ce49849db3ce677326a21f
1 parent
2cb0a345
Exists in
master
and in
4 other branches
New stacked_charge function used for agent display
Showing
3 changed files
with
102 additions
and
50 deletions
Show diff stats
app/db_mgr.py
... | ... | @@ -13,6 +13,21 @@ def agents(): |
13 | 13 | return all_agents |
14 | 14 | |
15 | 15 | |
16 | +def stacked_charges_by_agent(agent_id): | |
17 | + all_charges = {} | |
18 | + for (period_id, period_name) in db.session.execute("select id, name from period order by id"): | |
19 | + charge_by_project_req = """select p.name, c.charge_rate from project p left join | |
20 | + charge c on p.id = c.project_id and agent_id = {} and period_id={} | |
21 | + order by p.id""".format(agent_id, period_id) | |
22 | + period_charge = {} | |
23 | + for project_name, project_rate in db.session.execute(charge_by_project_req): | |
24 | + period_charge[project_name] = project_rate | |
25 | + all_charges[period_name]=period_charge | |
26 | + | |
27 | + pprint(all_charges) | |
28 | + return all_charges | |
29 | + | |
30 | + | |
16 | 31 | def charges_by_agent(agent_id): |
17 | 32 | # all_charges = db.session.query(Charge).all() |
18 | 33 | periods = db.session.execute("select name from period") | ... | ... |
app/main/routes.py
... | ... | @@ -94,11 +94,7 @@ def charge_add(): |
94 | 94 | @bp.route('/charge/agent/<agent_id>') |
95 | 95 | @role_required('service') |
96 | 96 | def charge_agent(agent_id): |
97 | - agent_charges = [] | |
98 | - for [period, charge] in db_mgr.charges_by_agent(agent_id): | |
99 | - agent_charges.append({"charge": charge, "periode": period}) | |
100 | - # agent_charges = [["charge", "periode"]]+db_mgr.charges_by_agent(agent_id)#agent_charges | |
101 | - resp = make_response(json.dumps(agent_charges)) | |
97 | + resp = make_response(json.dumps(db_mgr.stacked_charges_by_agent(agent_id))) | |
102 | 98 | resp.headers['Content-Type'] = 'application/json' |
103 | 99 | return resp |
104 | 100 | ... | ... |
app/main/templates/agent.html
... | ... | @@ -67,57 +67,98 @@ |
67 | 67 | |
68 | 68 | // On demande à D3JS de charger notre fichier |
69 | 69 | d3.json("{{url_for('main.charge_agent', agent_id=agent.id)}}").then(data => { |
70 | - // Conversion des caractères en nombres | |
71 | - data.forEach(d => d.charge = +d.charge); | |
72 | - | |
73 | - // Mise en relation du scale avec les données de notre fichier | |
74 | - // Pour l'axe X, c'est la liste des periodes | |
75 | - // Pour l'axe Y, c'est le max des charge | |
76 | - x.domain(data.map(d => d.periode)); | |
77 | - y.domain([0, 100]); | |
78 | - | |
79 | - // Ajout de l'axe X au SVG | |
80 | - // Déplacement de l'axe horizontal et du futur texte (via la fonction translate) au bas du SVG | |
81 | - // Selection des noeuds text, positionnement puis rotation | |
82 | - svg.append("g") | |
83 | - .attr("transform", "translate(0," + height + ")") | |
84 | - .call(d3.axisBottom(x).tickSize(5)) | |
85 | - .selectAll("text") | |
86 | - .style("text-anchor", "end") | |
87 | - .attr("dx", "-.8em") | |
88 | - .attr("dy", ".15em") | |
89 | - .attr("transform", "rotate(-65)"); | |
90 | - | |
91 | - | |
92 | - svg.append("text") | |
93 | - .attr("text-anchor", "end") | |
94 | - .attr("transform", "rotate(-90)") | |
95 | - .attr("y", -margin.left+60) | |
96 | - .attr("x", -margin.top-70) | |
97 | - .text("Charge (ETP)") | |
98 | - | |
99 | - | |
100 | - // Ajout de l'axe Y au SVG avec 6 éléments de légende en utilisant la fonction ticks (sinon D3JS en place autant qu'il peut). | |
101 | - svg.append("g") | |
102 | - .call(d3.axisLeft(y).ticks(6)); | |
103 | - | |
104 | - // Ajout des bars en utilisant les données de notre fichier data.tsv | |
105 | - // La largeur de la barre est déterminée par la fonction x | |
106 | - // La hauteur par la fonction y en tenant compte de la charge | |
107 | - // La gestion des events de la souris pour le popup | |
108 | - svg.selectAll(".bar") | |
109 | - .data(data) | |
70 | + | |
71 | + // waiting for structure of the form: | |
72 | + // | |
73 | + var periods = Object.keys(data) | |
74 | + var first_stacked_charges = Object.values(data)[0] | |
75 | + var projects = Object.keys(first_stacked_charges) | |
76 | + console.log(projects) | |
77 | + | |
78 | + // periods = data | |
79 | + var x = d3.scaleBand() | |
80 | + .domain(periods) | |
81 | + .range([0, width]) | |
82 | + .padding(0.2) | |
83 | + | |
84 | + svg.append('g') | |
85 | + .attr('transform', 'translate(20, ' + height + ')') | |
86 | + .call(d3.axisBottom(x).tickSizeOuter(0)); | |
87 | + | |
88 | + var y = d3.scaleLinear() | |
89 | + .domain([0, 100]) | |
90 | + .range([height, 0]) | |
91 | + | |
92 | + svg.append('g') | |
93 | + .attr('transform', 'translate(20, 0)') | |
94 | + .call(d3.axisLeft(y)) | |
95 | + | |
96 | + var color = d3.scaleOrdinal() | |
97 | + .domain(projects) | |
98 | + .range(['#e41a1c', '#377eb8', '#4daf4a', | |
99 | + "#800000", | |
100 | + "#FFFF00", | |
101 | + "#808000", | |
102 | + "#00FF00", | |
103 | + "#008000", | |
104 | + "#00FFFF", | |
105 | + "#008080", | |
106 | + "#0000FF", | |
107 | + "#000080", | |
108 | + "#FF00FF", | |
109 | + "#800080", | |
110 | + ]); | |
111 | + | |
112 | + var stack_generator = d3.stack() | |
113 | + .keys(projects) | |
114 | + | |
115 | + var stackable_data = [] | |
116 | + Object.keys(data).forEach( function (period){ | |
117 | + line = data[period]; | |
118 | + line['period']=period; | |
119 | + stackable_data.push(line) | |
120 | + }); | |
121 | + | |
122 | + var stacked_data = stack_generator(stackable_data) | |
123 | + | |
124 | + // var sel = d3.select("#demo2") | |
125 | + // .select('g') | |
126 | + // .selectAll('g.series') | |
127 | + // .data(stackedSeries) | |
128 | + // .join('g') | |
129 | + // .classed('series', true) | |
130 | + // .style('fill', (d) => colorScale(d.key)); | |
131 | + // | |
132 | + // sel.selectAll('rect') | |
133 | + // .data((d) => d) | |
134 | + // .join('rect') | |
135 | + // .attr('width', 40) | |
136 | + // .attr('y', (d) => yScale(d[1])) | |
137 | + // .attr('x', (d) => xScale(d.data.month) - 20) | |
138 | + // .attr('height', (d) => yScale(d[0]) - yScale(d[1])); | |
139 | + | |
140 | + svg.append('g') | |
141 | + .selectAll('g') | |
142 | + .data(stacked_data) | |
143 | + .enter().append('g') | |
144 | + .attr("fill", function (d) { | |
145 | + return color(d.key); | |
146 | + }) | |
147 | + .selectAll("rect") | |
148 | + // enter a second time = loop subgroup per subgroup to add all rectangles | |
149 | + .data(d => d) | |
110 | 150 | .enter().append("rect") |
111 | - .attr("class", "bar") | |
112 | - .attr("x", d => x(d.periode)) | |
151 | + .attr("x", d => x(d.data.period) + 20) | |
152 | + .attr("y", d => y(d[1])) | |
153 | + .attr("height", d => y(d[0]) - y(d[1])) | |
113 | 154 | .attr("width", x.bandwidth()) |
114 | - .attr("y", d => y(d.charge)) | |
115 | - .attr("height", d => height - y(d.charge)) | |
155 | + | |
116 | 156 | .on("mouseover", function (e, d) { |
157 | + console.log(d) | |
117 | 158 | div.transition() |
118 | 159 | .duration(200) |
119 | 160 | .style("opacity", .9); |
120 | - div.html("Charge: " + d.charge) | |
161 | + div.html("Charge: " + d) | |
121 | 162 | .style("left", (e.x + 10) + "px") |
122 | 163 | .style("top", (e.y - 50) + "px"); |
123 | 164 | }) | ... | ... |