datavis.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. function displayDataviz(data){
  2. console.log(data);
  3. let lane_array = [];
  4. let now = Date.now();
  5. let earlier = now;
  6. // ICI CACLCULER UNE HAUTEUR TOTAL EN FONCTION DU NOMBRE D'ACTIVISTE PAR LIGNE
  7. //height of items 10
  8. let item_height = 15;
  9. //object pour la hauteur
  10. // juste un array que je prendrai dans l'ordre des line
  11. const lineHeight_array = [];
  12. data.forEach(function(e){
  13. lane_array.push(e)
  14. if(e.start < earlier){
  15. earlier = e.start;
  16. }
  17. });
  18. let items_array = [];
  19. data.forEach(function(e){
  20. e.activist.forEach(function(d){
  21. items_array.push(d);
  22. if(d.start < earlier){
  23. earlier = d.start;
  24. }
  25. });
  26. if (e.activist.length*item_height > 50) {
  27. lineHeight_array.push(e.activist.length*item_height);
  28. }else{
  29. lineHeight_array.push(50);
  30. }
  31. });
  32. var lanes = lane_array,
  33. laneLength = lanes.length,
  34. items = items_array;
  35. var t1 = new Date(earlier);
  36. var t2 = new Date(now);
  37. var timeBegin = earlier,
  38. timeEnd = now ;
  39. //
  40. let pw = $(".post_content").width();
  41. var m = [20, 15, 15, 120], //top right bottom left
  42. w = pw - m[1] - m[3],
  43. h = sumArray(lineHeight_array) + (sumArray(lineHeight_array)/10) + 180,
  44. miniHeight = sumArray(lineHeight_array)/10 + 80,
  45. mainHeight = h - miniHeight - 40;
  46. //scales
  47. var x = d3.scaleLinear()
  48. .domain([timeBegin, timeEnd])
  49. .range([0, w]);
  50. var revert_x = d3.scaleLinear()
  51. .domain([0, w])
  52. .range([timeBegin, timeEnd]);
  53. var x1 = d3.scaleLinear()
  54. .range([0, w]);
  55. var y1 = d3.scaleLinear()
  56. .domain([0, laneLength])
  57. .range([0, mainHeight]);
  58. var y2 = d3.scaleLinear()
  59. .domain([0, laneLength])
  60. .range([0, miniHeight]);
  61. var chart = d3.select("#datavis")
  62. .append("svg")
  63. .attr("width", w + m[1] + m[3])
  64. .attr("height", h + m[0] + m[2])
  65. /*.attr("viewBox", '0 0 '+(h + m[0] + m[2])+' '+(w + m[1] + m[3])+'')*/
  66. .attr("class", "chart");
  67. chart.append("defs").append("clipPath")
  68. .attr("id", "clip")
  69. .append("rect")
  70. .attr("width", w)
  71. .attr("height", mainHeight);
  72. var main = chart.append("g")
  73. .attr("transform", "translate(" + m[3] + "," + m[0] + ")")
  74. .attr("width", w)
  75. .attr("height", mainHeight)
  76. .attr("class", "main");
  77. var mini = chart.append("g")
  78. .attr("transform", "translate(" + m[3] + "," + (mainHeight + m[0]+ 20) + ")")
  79. .attr("width", w-100)
  80. .attr("height", miniHeight)
  81. .attr("class", "mini");
  82. //main lanes and texts
  83. main.append("g").selectAll(".laneText")
  84. .data(lanes)
  85. .enter().append("text")
  86. .text(function(d) {return d.title;})
  87. .attr("x", -m[1])
  88. .attr("y", function(d, i) { if(d.lane == 0){ return lineHeight_array[i]/2}else{ return lineHeight_array[i]+sumArray(lineHeight_array, i-1)-lineHeight_array[i]/2};})
  89. .attr("dy", ".5ex")
  90. .attr("text-anchor", "end")
  91. .attr("class", "laneText");
  92. main.append("g").selectAll(".laneLines")
  93. .data(lanes)
  94. .enter().append("line")
  95. .attr("x1", m[1])
  96. .attr("y1", function(d,i) { if(d.lane == 0){ return lineHeight_array[i]}else{ return lineHeight_array[i]+sumArray(lineHeight_array, i-1)};})
  97. .attr("x2", w)
  98. .attr("y2", function(d,i) {if(d.lane == 0){return lineHeight_array[i]}else{return lineHeight_array[i]+sumArray(lineHeight_array, i-1)};})
  99. .attr("stroke", "black")
  100. const xaxis = d3.scaleLinear()
  101. .domain([timeBegin, timeEnd])
  102. .range([0, w]);
  103. mini.append("g")
  104. .attr("transform", "translate(0," + miniHeight + ")")
  105. .call(d3.axisBottom(xaxis).ticks(t2.getFullYear()-t1.getFullYear()).tickFormat(d3.timeFormat('%Y')))
  106. .selectAll("text")
  107. /*.attr("transform", "translate(-10,10)rotate(-45)")*/
  108. .style("text-anchor", "center")
  109. .style("font-size", 20)
  110. .style("fill", "black");
  111. // coalition
  112. // adapt in display
  113. /*var coa = main.append("g").selectAll("rect")
  114. .data(lanes)
  115. .enter().append("rect")
  116. .attr("class", "coalition")
  117. .attr("x", function(d) {var date = new Date(d.start); return x(d.start);})
  118. .attr("y", function(d) {return y1(d.lane) + 10;})
  119. .attr("height", function(d) {return .8 * y1(1);})
  120. .attr("width", function(d) { return x(d.end) - x(d.start);})
  121. .attr("pos", function(d) {return d.lane });*/
  122. //mini lanes and texts
  123. mini.append("g").selectAll(".laneLines")
  124. .data(items)
  125. .enter().append("line")
  126. .attr("x1", m[1])
  127. .attr("y1", function(d) {return y2(d.lane);})
  128. .attr("x2", w)
  129. .attr("y2", function(d) {return y2(d.lane);})
  130. .attr("stroke", "lightgray");
  131. mini.append("g").selectAll(".laneText")
  132. .data(lanes)
  133. .enter().append("text")
  134. .text(function(d) {return d.title;})
  135. .attr("x", -m[1])
  136. .attr("y", function(d, i) {return y2(i + .5);})
  137. .attr("dy", ".5ex")
  138. .attr("text-anchor", "end")
  139. .attr("class", "laneText");
  140. var itemCoa = main.append("g").attr("clip-path", "url(#clip)");
  141. var itemCircles = main.append("g")
  142. .attr("clip-path", "url(#clip)");
  143. var itemRects = main.append("g")
  144. .attr("clip-path", "url(#clip)");
  145. var axisMain = main.append("g")
  146. .attr("clip-path", "url(#clip)");
  147. coa = mini.append("g").selectAll("rect")
  148. .data(lanes)
  149. .enter().append("rect")
  150. .attr("class", "coalition")
  151. .attr("x", function(d) { return x(d.start);})
  152. .attr("y", function(d) {return y2(d.lane) + 2;})
  153. .attr("height", function(d) {return .8 * y2(1);})
  154. .attr("width", function(d) { return x(d.end) - x(d.start);})
  155. .attr("pos", function(d) {return d.lane });
  156. //mini item rects
  157. mini.append("g").selectAll("miniItems")
  158. .data(items)
  159. .enter().append("rect")
  160. .attr("class", function(d) {return "markers";})
  161. .attr("x", function(d) {return x(d.start);})
  162. /*.attr("y", function(d, i) {let l1 = d.lane+1; let increments = (y2(l1)-y2(d.lane)) / (lanes[d.lane].activist.length)*i; return y2(d.lane)+increments;})*/
  163. .attr("y", function(d){ let idx = lanes[d.lane].activist.indexOf(d); let increments = y2(1) / (lanes[d.lane].activist.length)*idx; return y2(d.lane)+(increments) })
  164. .attr("width", function(d) {return x(d.end) - x(d.start);})
  165. .attr("height", 1);
  166. mini.append("g").selectAll("miniCircle")
  167. .data(items)
  168. .enter().append("circle")
  169. .attr("class", function(d) {return "markers";})
  170. .attr("cx", function(d) {return x(d.start);})
  171. /*.attr("y", function(d, i) {let l1 = d.lane+1; let increments = (y2(l1)-y2(d.lane)) / (lanes[d.lane].activist.length)*i; return y2(d.lane)+increments;})*/
  172. .attr("cy", function(d){ let idx = lanes[d.lane].activist.indexOf(d); let increments = y2(1) / (lanes[d.lane].activist.length)*idx; return y2(d.lane)+(increments) })
  173. .attr("r", 1);
  174. //mini labels
  175. /*mini.append("g").selectAll(".miniLabels")
  176. .data(items)
  177. .enter().append("text")
  178. .text(function(d) {return d.id;})
  179. .attr("x", function(d) {return x(d.start);})
  180. .attr("y", function(d, i) { let l1 = d.lane+1; let increments = (y2(l1)-y2(d.lane)) / (lanes[d.lane].activist.length)*i; return y2(d.lane)+increments;})
  181. .attr("dy", ".5ex");
  182. */
  183. // data interaction
  184. $("body").on("mouseover", ".label_info", function(){
  185. let id = $(this).data("id");
  186. let elem = $("body").find('.miniItem[data-id="'+id+'"]');
  187. let c = $("body").find('.miniCircle[data-id="'+id+'"]');
  188. let y = parseFloat(elem.attr("y"))-10;
  189. elem.css({
  190. "y" :y,
  191. "height": "25px",
  192. "fill": 'black'
  193. });
  194. /*c.css({
  195. "r" : "13px",
  196. "fill": 'black'
  197. });*/
  198. $(this).css({
  199. "font" : "15px sans-serif",
  200. "fill": '#e94d1a'
  201. });
  202. });
  203. $("body").on("mouseleave", ".label_info", function(){
  204. let id = $(this).data("id");
  205. let elem = $("body").find('.miniItem[data-id="'+id+'"]');
  206. let c = $("body").find('.miniCircle[data-id="'+id+'"]');
  207. let y = parseFloat(elem.attr("y"));
  208. elem.css({
  209. "y" :y,
  210. "height" : "10px",
  211. "fill": '#e94d1a'
  212. });
  213. /*c.css({
  214. "r" : "5px",
  215. "fill": '#e94d1a'
  216. });*/
  217. $(this).css({
  218. "font" : "10px sans-serif",
  219. "fill": 'black'
  220. })
  221. });
  222. $("body").on("mouseover", ".miniItem", function(){
  223. let id = $(this).data("id");
  224. let elem = $("body").find('.label_info[data-id="'+id+'"]');
  225. let c = $("body").find('.miniCircle[data-id="'+id+'"]');
  226. let y = parseFloat($(this).attr("y"))-10;
  227. elem.css({
  228. "font" : "15px sans-serif",
  229. "fill": '#e94d1a'
  230. });
  231. /*c.css({
  232. "r" : "13px",
  233. "fill": 'black'
  234. });*/
  235. $(this).css({
  236. "y" :y,
  237. "height": "25px",
  238. "fill": 'black'
  239. });
  240. });
  241. $("body").on("mouseleave", ".miniItem", function(){
  242. let id = $(this).data("id");
  243. let elem = $("body").find('.label_info[data-id="'+id+'"]');
  244. let c = $("body").find('.miniCircle[data-id="'+id+'"]');
  245. let y = parseFloat($(this).attr("y"));
  246. elem.css({
  247. "font" : "10px sans-serif",
  248. "fill": 'black'
  249. });
  250. /*c.css({
  251. "r" : "5px",
  252. "fill": '#e94d1a'
  253. });*/
  254. $(this).css({
  255. "y" :y,
  256. "height" : "10px",
  257. "fill": '#e94d1a'
  258. })
  259. });
  260. // brush function
  261. /*const brush = d3.brushX().on('brush', handleBrush);
  262. initBrush();*/
  263. // mini.select(".brush")
  264. // .call(brush.extent([[0, 0], [w, miniHeight]]));
  265. // Selecting SVG element
  266. /*mini.call(d3.brush().move, [[0, 0], [w, miniHeight]])*/
  267. /*function initBrush() {
  268. mini.append("g")
  269. .attr("class", "brush")
  270. .call(brush.extent([[0, 0], [w, miniHeight]]));
  271. }*/
  272. // brush old
  273. var brush = d3.brushX()
  274. .on("brush", handleBrush)
  275. mini.append("g")
  276. .attr("class", "brush")
  277. .call(brush.extent([[0, 0], [w, miniHeight]]));
  278. handleBrush();
  279. function handleBrush() {
  280. var minExtent = d3.brushSelection(this) == null ? 0 : d3.brushSelection(this)[0] ;
  281. var maxExtent = d3.brushSelection(this) == null ? w : d3.brushSelection(this)[1] ;
  282. var rects, points, labels,
  283. visItems = items.filter(function(d) {return x(d.start) < maxExtent && x(d.end) > minExtent;});
  284. vislanes = lanes.filter(function(d) {return x(d.start) < maxExtent && x(d.end) > minExtent;});
  285. var checkable = [];
  286. visItems.forEach(function(e){ checkable.push(e.id)});
  287. vislanes.forEach(function(e){
  288. e.activist.forEach(function(d){
  289. if(checkable.includes(d.id) == false){
  290. //console.log(d.id);
  291. const index = e.activist.indexOf(d);
  292. if (index == -1) {
  293. e.activist.splice(index, 1);
  294. }
  295. }
  296. });
  297. });
  298. /* */
  299. x1.domain([revert_x(minExtent), revert_x(maxExtent)]);
  300. //update main item rects
  301. rects = itemRects.selectAll("rect")
  302. .data(visItems, function(d) { return d.id; })
  303. .attr("x", function(d) {return x1(d.start);})
  304. .attr("width", function(d) {return x1(d.end) - x1(d.start);});
  305. rects.enter().append("rect")
  306. .attr("class", function(d) {return "miniItem";})
  307. .attr('data-id',function(d,i) {return i+'-'+d.lane+'_'+d.id;} )
  308. .attr('data-ref',function(d,i) {return d.pos+'_'+d.id.replace(/\s/g, '');} )
  309. .attr("x", function(d) {return x1(d.start);})
  310. .attr("y", function(d) {
  311. let idx = lanes[d.lane].activist.indexOf(d);
  312. let increments = ( lineHeight_array[d.lane]-15) / (lanes[d.lane].activist.length)*idx;
  313. return sumArray(lineHeight_array, d.lane, true)+(increments)+7
  314. })
  315. .attr("width", function(d) {return x1(d.end) - x1(d.start);})
  316. .attr("height", function(d) {return 10;});
  317. rects.exit().remove();
  318. //axis
  319. const bigAxis = d3.scaleLinear()
  320. .domain([revert_x(minExtent), revert_x(maxExtent)])
  321. .range([0, w]);
  322. let t2 =new Date(revert_x(maxExtent));
  323. let t1 =new Date(revert_x(minExtent));
  324. axisMain.attr("transform", "translate(0," + (mainHeight - 50) +")")
  325. .call(d3.axisBottom(bigAxis).ticks(t2.getFullYear()-t1.getFullYear()).tickFormat(d3.timeFormat('%Y')))
  326. .selectAll("text")
  327. /*.attr("transform", "translate(-10,10)rotate(-45)")*/
  328. .style("text-anchor", "center")
  329. .style("font-size", 20)
  330. .style("fill", "black");
  331. axisMain.exit().remove();
  332. //update the item labels
  333. labels = itemRects.selectAll("text")
  334. .data(visItems, function (d) { return d.id; })
  335. .attr("x", function(d) {return x1(Math.max(d.start, revert_x(minExtent) + 2))+10;});
  336. labels.enter().append("text")
  337. .text(function(d) {return d.id;})
  338. .attr('class', 'label_info')
  339. .attr('data-id',function(d,i) {return i+'-'+d.lane+'_'+d.id;} )
  340. .attr('data-ref',function(d,i) {return d.pos+'_'+d.id.replace(/\s/g, '');} )
  341. .attr("x", function(d) {return x1(Math.max(d.start, revert_x(minExtent)));})
  342. .attr("y", function(d) {
  343. let idx = lanes[d.lane].activist.indexOf(d);
  344. let increments = (lineHeight_array[d.lane]-15) / (lanes[d.lane].activist.length)*idx;
  345. return sumArray(lineHeight_array, d.lane, true)+(increments)+15
  346. })
  347. .attr("text-anchor", "start");
  348. labels.exit().remove();
  349. //circles
  350. ccs = itemCircles.selectAll("circle")
  351. .data(visItems, function(d) { return d.id; })
  352. .attr("cx", function(d) {return x1(Math.max(d.start, revert_x(minExtent)));});
  353. /*.attr("width", function(d) {return x1(d.end) - x1(d.start);});*/
  354. ccs.enter().append("circle")
  355. .attr("class", function(d) {return "miniCircle";})
  356. .attr('data-id',function(d,i) {return i+'-'+d.lane+'_'+d.id;} )
  357. .attr("cx", function(d) {return x1(Math.max(d.start, revert_x(minExtent)))-7;})
  358. .attr("cy", function(d) {
  359. let idx = lanes[d.lane].activist.indexOf(d);
  360. let increments = (( lineHeight_array[d.lane] -15 ) / (lanes[d.lane].activist.length))*idx;
  361. return sumArray(lineHeight_array, d.lane, true)+(increments)+12
  362. })
  363. .attr("r", function(d,i) {
  364. let id = i+'-'+d.lane+'_'+d.id;
  365. let itemw = $("body").find('.miniItem[data-id="'+id+'"]').attr("width");
  366. let lbw = $("body").find('.label_info[data-id="'+id+'"]')[0].getBoundingClientRect().width;
  367. if (lbw > itemw && itemw < 8 ) {
  368. return 5;
  369. }else{
  370. return 0;
  371. }
  372. });
  373. ccs.exit().remove();
  374. //redraw coa lane
  375. coa = itemCoa.selectAll("rect")
  376. .data(lanes)
  377. .attr("x", function(d) {return x1(d.start);})
  378. .attr("width", function(d) {return x1(d.end) - x1(d.start);});
  379. coa.enter().append("rect")
  380. .attr("class", "coalition")
  381. .attr("x", function(d) {return x1(d.start);})
  382. .attr("y", function(d, i ) {return sumArray(lineHeight_array, i, true)+5;})
  383. .attr("height", function(d, i) {return lineHeight_array[i]-10;})
  384. .attr("width", function(d) {return x1(d.end) - x1(d.start);})
  385. .attr("pos", function(d) {return d.lane });
  386. coa.exit().remove();
  387. labelcoa = itemCoa.selectAll("text")
  388. .data(lanes)
  389. .attr("x", function(d) {return x1(Math.max(d.start, revert_x(minExtent)))+20;});
  390. labelcoa.enter().append("text")
  391. .text(function(d) {return d.coa_name})
  392. .attr('class', 'coa_name')
  393. .attr('fill','white')
  394. .attr("y", function(d, i ) {return sumArray(lineHeight_array, i, true)+lineHeight_array[i]/2+10;})
  395. labelcoa.exit().remove();
  396. }
  397. function sumArray(array, to, strict){
  398. let s = 0;
  399. if (to == null) {
  400. array.forEach(function(e){
  401. s = s+e;
  402. });
  403. }else{
  404. if (strict == false || strict == null) {
  405. for (var i = 0; i <= to; i++) {
  406. s = s+array[i];
  407. }
  408. }else{
  409. for (var i = 0; i < to; i++) {
  410. s = s+array[i];
  411. }
  412. }
  413. }
  414. return s;
  415. }
  416. }