corpus.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. /**
  2. * @Author: Bachir Soussi Chiadmi <bach>
  3. * @Date: 18-12-2017
  4. * @Email: bachir@figureslibres.io
  5. * @Filename: corpus.js
  6. * @Last modified by: bach
  7. * @Last modified time: 20-12-2017
  8. * @License: GPL-V3
  9. */
  10. /**
  11. * depends on :
  12. *
  13. * physics.js : http://jonobr1.com/Physics/#
  14. * EaselJS : https://createjs.com/docs/easeljs/modules/EaselJS.html
  15. *
  16. */
  17. (function($) {
  18. EdlpCorpus = function(){
  19. var _activated = true;
  20. var _$body = $('body');
  21. var _$container = _$body;
  22. var _$canvas = $('<canvas id="corpus-map">').appendTo(_$container);
  23. var _canvas = _$canvas[0];
  24. var _ctx = _canvas.getContext('2d');
  25. var _canvas_props = {
  26. 'margin_top':100,
  27. 'margin_right':0,
  28. 'margin_bottom':100,
  29. 'margin_left':0
  30. };
  31. var _physics = new Physics();
  32. // var _stage = new createjs.Stage('corpus-map');
  33. var _nodes = [];
  34. var _articles_nodes = [];
  35. var _no_articles_nodes = [];
  36. var _nodes_by_entries = {};
  37. var _nodes_by_nid = {};
  38. // var _particules = [];
  39. // var _base_radius = 3; // nodes radius (real radius, not diametre)
  40. var _p_velocity_factor = 0.5;
  41. var _mouse_in = true;
  42. var _m_pos = {x:0, y:0};
  43. var _node_hover_id = -1;
  44. var _node_opened_id = -1;
  45. var _$entrees_block = $('#block-edlpentreesblock');
  46. var _$entrees_block_termlinks = $('a.term-link', _$entrees_block);
  47. var _$articles_link;
  48. var _node_pop_up;
  49. // Colors depend on drupalSettings loaded by edlp_corpus.module
  50. var _ecolors = drupalSettings.edlp_corpus.colors;
  51. console.log('Corpus : _ecolors', _ecolors);
  52. // Physics
  53. var _attracter,
  54. _repulser,
  55. _repulser_center,
  56. _scrambler_TL,
  57. _scrambler_TR,
  58. _scrambler_BR,
  59. _scrambler_BL,
  60. _scrambler_CL,
  61. _scrambler_CR;
  62. // ____ _ __
  63. // / _/___ (_) /______
  64. // / // __ \/ / __/ ___/
  65. // _/ // / / / / /_(__ )
  66. // /___/_/ /_/_/\__/____/
  67. function init(){
  68. console.log("EdlpCorpus init()");
  69. // console.log("document", document);
  70. initMap();
  71. };
  72. function initMap(){
  73. console.log("EdlpCorpus initMap()");
  74. // console.log('_physics',_physics);
  75. initCanvas();
  76. if(_activated){
  77. loadCorpus();
  78. }else{
  79. _$canvas.addClass('de-activated');
  80. }
  81. };
  82. // ______
  83. // / ____/___ _____ _ ______ ______
  84. // / / / __ `/ __ \ | / / __ `/ ___/
  85. // / /___/ /_/ / / / / |/ / /_/ (__ )
  86. // \____/\__,_/_/ /_/|___/\__,_/____/
  87. function initCanvas(){
  88. // resize the canvas to fill browser window dynamically
  89. window.addEventListener('resize', onResizeCanvas, false);
  90. onResizeCanvas();
  91. };
  92. function onResizeCanvas() {
  93. _canvas.width = window.innerWidth;
  94. _canvas.height = window.innerHeight;
  95. for (var i = 0; i < _nodes.length; i++) {
  96. _nodes[i].onResizeCanvas();
  97. // move _attracter and _repulser to the center again
  98. resizePhysics();
  99. }
  100. };
  101. // ___ _
  102. // / | (_)___ __ __
  103. // / /| | / / __ `/ |/_/
  104. // / ___ | / / /_/ /> <
  105. // /_/ |_|_/ /\__,_/_/|_|
  106. // /___/
  107. function loadCorpus(){
  108. // console.log('drupalSettings',drupalSettings);
  109. // console.log('window.location', window.location);
  110. var path = window.location.origin + drupalSettings.basepath + "edlp/corpus";
  111. $.getJSON(path, {})
  112. .done(function(data){
  113. onCorpusLoaded(data);
  114. })
  115. .fail(function(jqxhr, textStatus, error){
  116. onCorpusLoadError(jqxhr, textStatus, error);
  117. });
  118. };
  119. function onCorpusLoadError(jqxhr, textStatus, error){
  120. console.warn('corpus load failed', jqxhr.responseText);
  121. };
  122. function onCorpusLoaded(data){
  123. console.log('corpus loaded : data', data);
  124. // console.log('first node', data.nodes[0]);
  125. // buildParticles(data.nodes);
  126. initNodePopup();
  127. initArtilesLink();
  128. initPhysics();
  129. buildNodes(data.nodes);
  130. initEvents();
  131. startAnime();
  132. };
  133. // ___ _ _
  134. // | _ \ |_ _ _ __(_)__ ___
  135. // | _/ ' \ || (_-< / _(_-<
  136. // |_| |_||_\_, /__/_\__/__/
  137. // |__/
  138. function initPhysics(){
  139. _attracter = _physics.makeParticle(1000);
  140. _attracter.fixed = true;
  141. _repulser_center = _physics.makeParticle(100);
  142. _repulser_center.fixed = true;
  143. _scrambler_TL = _physics.makeParticle(100);
  144. _scrambler_TL.fixed = true;
  145. _scrambler_TR = _physics.makeParticle(100);
  146. _scrambler_TR.fixed = true;
  147. _scrambler_BR = _physics.makeParticle(100);
  148. _scrambler_BR.fixed = true;
  149. _scrambler_BL = _physics.makeParticle(100);
  150. _scrambler_BL.fixed = true;
  151. _scrambler_CR = _physics.makeParticle(100);
  152. _scrambler_CR.fixed = true;
  153. _scrambler_CL = _physics.makeParticle(100);
  154. _scrambler_CL.fixed = true;
  155. // move _attracter and _repulser on window resize
  156. resizePhysics();
  157. };
  158. function resizePhysics(){
  159. _attracter.position = {x:_canvas.width/2, y:_canvas.height/2};
  160. _repulser_center.position = {x:_canvas.width/2, y:_canvas.height/2};
  161. _scrambler_TL.position = {x:-100, y:-100};
  162. _scrambler_TR.position = {x:_canvas.width+100, y:-100};
  163. _scrambler_BR.position = {x:_canvas.width+100, y:_canvas.height+100};
  164. _scrambler_BL.position = {x:-100, y:_canvas.height+100};
  165. _scrambler_CL.position = {x:-100, y:_canvas.height/2};
  166. _scrambler_CR.position = {x:_canvas.width+100, y:_canvas.height/2};
  167. // TODO: move _attracter and _repulser on window resize
  168. };
  169. // _ __ __
  170. // / | / /___ ____/ /__ _____
  171. // / |/ / __ \/ __ / _ \/ ___/
  172. // / /| / /_/ / /_/ / __(__ )
  173. // /_/ |_/\____/\__,_/\___/____/
  174. function buildNodes(nodes){
  175. console.log("buildNodes", nodes);
  176. var d;
  177. for (var i in nodes) {
  178. d = i < 1 ? true : false;
  179. // _nodes.push(new Node(i,nodes[i],d));
  180. new Node(i,nodes[i],d);
  181. }
  182. console.log('_nodes',_nodes);
  183. console.log('_articles_nodes',_articles_nodes);
  184. console.log('_no_articles_nodes',_no_articles_nodes);
  185. console.log('_nodes_by_entries', _nodes_by_entries);
  186. };
  187. function Node(i,node,d){
  188. this.id = i;
  189. for(key in node)
  190. this[key] = node[key];
  191. // record the node in different lists
  192. _nodes.push(this);
  193. _nodes_by_nid[this.nid] = this;
  194. if(this.has_article == 1){
  195. _articles_nodes.push(this);
  196. }else{
  197. _no_articles_nodes.push(this);
  198. }
  199. for (var j = 0; j < this.entrees.length; j++) {
  200. if(typeof _nodes_by_entries[this.entrees[j]] == 'undefined')
  201. _nodes_by_entries[this.entrees[j]] = [];
  202. _nodes_by_entries[this.entrees[j]].push(this);
  203. }
  204. this.debug = d;
  205. this.mass = Math.max(1, this.entrees.length); //1;
  206. this.velocity_threshold = 0.01;
  207. // define radius regarding entries length
  208. switch(true){
  209. case this.entrees.length > 3:
  210. this.r = 10;
  211. break;
  212. case this.entrees.length > 1 && this.entrees.length <= 3:
  213. this.r = 7;
  214. break;
  215. default:
  216. this.r = 4;
  217. break;
  218. }
  219. this.e_color = 'e_col_'+this.entrees[Math.floor(Math.random(this.entrees.length))];
  220. this.hover = false;
  221. this.opened = false;
  222. this.faded = false;
  223. this.center = false;
  224. this.aside = false;
  225. this.scrambling = false;
  226. // prototypes
  227. if (typeof Node.initialized == "undefined") {
  228. Node.prototype.init = function(){
  229. this.calcWallLimits();
  230. this.x = this.wall_limits.left + Math.random()*(this.wall_limits.right - this.wall_limits.left);
  231. this.y = this.wall_limits.top + Math.random()*(this.wall_limits.bottom - this.wall_limits.top);
  232. this.initPhysics();
  233. // if(this.id == '620'){
  234. // _node_pop_up.setNode(this);
  235. // }
  236. };
  237. Node.prototype.initPhysics = function(){
  238. // particule
  239. this.p = _physics.makeParticle(this.mass, this.x, this.y);
  240. this.p.velocity = new Physics.Vector((Math.random()-0.5)*_p_velocity_factor, (Math.random()-0.5)*_p_velocity_factor);
  241. // attracter
  242. this.attract = _physics.makeAttraction(_attracter, this.p, 1000, _canvas.width*2);
  243. this.attract.on = false;
  244. // repulsers
  245. this.repulse_center = _physics.makeAttraction(_repulser_center, this.p, -100, _canvas.height/2);
  246. this.repulse_center.on = false;
  247. this.scramble_TL = _physics.makeAttraction(_scrambler_TL, this.p, -100, _canvas.height/3);
  248. this.scramble_TL.on = false;
  249. this.scramble_TR = _physics.makeAttraction(_scrambler_TR, this.p, -100, _canvas.height/3);
  250. this.scramble_TR.on = false;
  251. this.scramble_BR = _physics.makeAttraction(_scrambler_BR, this.p, -100, _canvas.height/3);
  252. this.scramble_BR.on = false;
  253. this.scramble_BL = _physics.makeAttraction(_scrambler_BL, this.p, -100, _canvas.height/3);
  254. this.scramble_BL.on = false;
  255. this.scramble_CR = _physics.makeAttraction(_scrambler_CR, this.p, -100, _canvas.height/3);
  256. this.scramble_CR.on = false;
  257. this.scramble_CL = _physics.makeAttraction(_scrambler_CL, this.p, -100, _canvas.height/3);
  258. this.scramble_CL.on = false;
  259. };
  260. Node.prototype.calcWallLimits = function(){
  261. this.wall_limits = {
  262. top: _canvas_props.margin_top +this.r,
  263. right: _canvas.width -_canvas_props.margin_right -this.r,
  264. bottom: _canvas.height -_canvas_props.margin_bottom -this.r,
  265. left: _canvas_props.margin_left +this.r
  266. }
  267. };
  268. Node.prototype.onResizeCanvas = function(){
  269. this.calcWallLimits();
  270. // TODO: when canvas is smaller what about nodes hors champs, they are coming back alone but it's too long
  271. };
  272. Node.prototype.onUpdate = function(){
  273. // this.p.velocity.multiplyScalar(0.99);
  274. if(!this.p.resting()){
  275. // this.checkVelocityThreshold();
  276. this.checkWallBouncing();
  277. this.updatePos();
  278. }
  279. if(_mouse_in && !this.aside)
  280. this.checkMouse();
  281. // if(this.debug)
  282. // console.log("Node pos: ", {x:this.x, y:this.y});
  283. this.draw();
  284. };
  285. Node.prototype.checkVelocityThreshold = function(){
  286. if(!this.centered || !this.aside){
  287. if (Math.abs(this.p.velocity.x) < this.velocity_threshold
  288. && Math.abs(this.p.velocity.y) < this.velocity_threshold){
  289. this.p.velocity.multiplyScalar(0);
  290. // this.p.makeFixed();
  291. }
  292. }
  293. };
  294. Node.prototype.checkWallBouncing = function(){
  295. switch(true){
  296. case this.x < this.wall_limits.left && this.p.velocity.x < 0:
  297. this.p.position.x = this.wall_limits.left;
  298. this.p.velocity.multiplyScalarXY(-1, 1).multiplyScalar(0.75);
  299. break;
  300. case this.x > this.wall_limits.right && this.p.velocity.x > 0:
  301. this.p.position.x = this.wall_limits.right;
  302. this.p.velocity.multiplyScalarXY(-1, 1).multiplyScalar(0.75);
  303. break;
  304. case this.y < this.wall_limits.top && this.p.velocity.y < 0 :
  305. this.p.position.y = this.wall_limits.top;
  306. this.p.velocity.multiplyScalarXY(1,-1).multiplyScalar(0.75);
  307. break;
  308. case this.y > this.wall_limits.bottom && this.p.velocity.y > 0 :
  309. this.p.position.y = this.wall_limits.bottom;
  310. this.p.velocity.multiplyScalarXY(1,-1).multiplyScalar(0.75);
  311. break;
  312. }
  313. };
  314. Node.prototype.updatePos = function(){
  315. this.x = this.p.position.x;
  316. this.y = this.p.position.y;
  317. };
  318. Node.prototype.checkMouse = function(){
  319. if( _m_pos.x > this.x - this.r
  320. && _m_pos.x < this.x + this.r
  321. && _m_pos.y > this.y - this.r
  322. && _m_pos.y < this.y + this.r){
  323. if(_node_hover_id == -1 || _node_hover_id !== this.id){
  324. // console.log("Node hover", this.id);
  325. this.hover = true;
  326. _node_hover_id = this.id;
  327. _node_pop_up.setNode(this);
  328. }
  329. }else{
  330. this.hover = false;
  331. if (_node_hover_id == this.id) {
  332. _node_hover_id = -1;
  333. _node_pop_up.removeNode();
  334. }
  335. }
  336. };
  337. Node.prototype.open = function(){
  338. this.opened = true;
  339. };
  340. Node.prototype.close = function(){
  341. this.opened = false;
  342. };
  343. Node.prototype.fade = function(){
  344. this.faded = true;
  345. };
  346. Node.prototype.unFade = function(){
  347. this.faded = false;
  348. };
  349. Node.prototype.setCenteredOnEntree = function(tid){
  350. this.e_color = 'e_col_'+tid;
  351. this.setCentered();
  352. };
  353. Node.prototype.setCentered = function(){
  354. this.center = true;
  355. this.stopScrambling();
  356. this.unsetAside();
  357. this.attract.on = true;
  358. }
  359. Node.prototype.unsetCentered = function(){
  360. this.center = false;
  361. this.attract.on = false;
  362. }
  363. Node.prototype.setAside = function(){
  364. this.aside = true;
  365. this.fade();
  366. this.stopScrambling();
  367. this.unsetCentered();
  368. this.repulse_center.on = true;
  369. }
  370. Node.prototype.unsetAside = function(){
  371. this.aside = false;
  372. this.unFade();
  373. this.repulse_center.on = false;
  374. }
  375. Node.prototype.scramble = function(){
  376. this.scrambling = true;
  377. this.unsetCentered();
  378. this.unsetAside();
  379. this.scramble_TL.on = true;
  380. this.scramble_TR.on = true;
  381. this.scramble_BR.on = true;
  382. this.scramble_BL.on = true;
  383. // this.scramble_CR.on = true;
  384. // this.scramble_CL.on = true;
  385. }
  386. Node.prototype.stopScrambling = function(){
  387. this.scrambling = false;
  388. this.scramble_TL.on = false;
  389. this.scramble_TR.on = false;
  390. this.scramble_BR.on = false;
  391. this.scramble_BL.on = false;
  392. // this.scramble_CR.on = false;
  393. // this.scramble_CL.on = false;
  394. }
  395. Node.prototype.draw = function(){
  396. // carre plein
  397. // clouleur aléatoire ds les entrees
  398. // 3 tailles :
  399. // - 1 entree : petit carre 5px
  400. // - 2-3 entrees : moyen 7.5px
  401. // - >3 entrees : grand 10px
  402. // actif entouré de rouge
  403. _ctx.beginPath();
  404. _ctx.globalAlpha = this.faded ? 0.1 : 1;
  405. // _ctx.fillStyle = !this.p.resting() ? _ecolors[this.e_color] : 'rgb(0, 0, 0)';
  406. _ctx.fillStyle = _ecolors[this.e_color];
  407. _ctx.fillRect(this.x - this.r,this.y - this.r,this.r*2,this.r*2);
  408. if(this.opened){
  409. _ctx.lineWidth = '1px';
  410. _ctx.strokeStyle = 'rgb(255,0,0)';
  411. _ctx.strokeRect(this.x - this.r-3,this.y - this.r-3,this.r*2+6,this.r*2+6);
  412. }
  413. _ctx.globalAlpha = 1;
  414. _ctx.closePath();
  415. };
  416. Node.initialized = true;
  417. }
  418. this.init();
  419. };
  420. // TODO: we may convert a lot of computation into a web worker https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
  421. function checkParticulesCollisions(){
  422. // pre create vars to save memory;
  423. var d, full_rad,
  424. newVelX1, newVelY1, newVelX2, newVelY2,
  425. makeup, angle;
  426. // colisions between _particules
  427. for (var n = 0; n < _nodes.length; n++) {
  428. if(_nodes[n].scrambling) continue;
  429. for (var q = n+1; q < _nodes.length; q++) {
  430. if(q===n) continue;
  431. // avoid impact between center and aside particules
  432. if((_nodes[n].center && _nodes[q].aside) || (_nodes[n].aside && _nodes[q].center))
  433. continue;
  434. // avoid impact between two centered particulses that comes to the center
  435. if(_nodes[n].center && _nodes[q].center){
  436. if(Math.min(_nodes[n].p.distanceTo(_attracter), _nodes[q].p.distanceTo(_attracter)) > 300){
  437. if( Math.random()>0.3 ) continue;
  438. }
  439. }
  440. d = _nodes[n].p.distanceTo(_nodes[q].p);
  441. full_rad = _nodes[n].r + _nodes[q].r;
  442. // if not colliding skip following
  443. if(d > full_rad) continue;
  444. // apply new forces if colliding
  445. newVelX1 = (_nodes[n].p.velocity.x * (_nodes[n].p.mass - _nodes[q].p.mass)
  446. + (2 * _nodes[q].p.mass * _nodes[q].p.velocity.x)) / (_nodes[n].p.mass + _nodes[q].p.mass);
  447. newVelY1 = (_nodes[n].p.velocity.y * (_nodes[n].p.mass - _nodes[q].p.mass)
  448. + (2 * _nodes[q].p.mass * _nodes[q].p.velocity.y)) / (_nodes[n].p.mass + _nodes[q].p.mass);
  449. newVelX2 = (_nodes[q].p.velocity.x * (_nodes[q].p.mass - _nodes[n].p.mass)
  450. + (2 * _nodes[n].p.mass * _nodes[n].p.velocity.x)) / (_nodes[n].p.mass + _nodes[q].p.mass);
  451. newVelY2 = (_nodes[q].p.velocity.y * (_nodes[q].p.mass - _nodes[n].p.mass)
  452. + (2 * _nodes[n].p.mass * _nodes[n].p.velocity.y)) / (_nodes[n].p.mass + _nodes[q].p.mass);
  453. _nodes[n].p.velocity.x = newVelX1;
  454. _nodes[n].p.velocity.y = newVelY1;
  455. _nodes[q].p.velocity.x = newVelX2;
  456. _nodes[q].p.velocity.y = newVelY2;
  457. // slow down particule on impact
  458. _nodes[n].p.velocity.multiplyScalar(_nodes[n].center ? 0.90 : 0.90);
  459. _nodes[q].p.velocity.multiplyScalar(_nodes[q].center ? 0.90 : 0.90);
  460. // move particles if they overlap
  461. if (d < full_rad) {
  462. makeup = (full_rad/2 - d/2)*1.2;
  463. angle = Math.atan2(_nodes[q].p.position.y - _nodes[n].p.position.y, _nodes[q].p.position.x - _nodes[n].p.position.x);
  464. _nodes[q].p.position.x += makeup * Math.cos(angle);
  465. _nodes[q].p.position.y += makeup * Math.sin(angle);
  466. angle += Math.PI;
  467. _nodes[n].p.position.x += makeup * Math.cos(angle);
  468. _nodes[n].p.position.y += makeup * Math.sin(angle);
  469. }
  470. }
  471. }
  472. };
  473. // show opened audio node
  474. function openNode(id){
  475. closeNode();
  476. _node_opened_id = id;
  477. _nodes[id].open();
  478. }
  479. function closeNode(){
  480. if(_node_opened_id != -1){
  481. _nodes[_node_opened_id].close();
  482. _node_opened_id = -1;
  483. }
  484. }
  485. // ___ _
  486. // | __|_ _| |_ _ _ ___ ___ ___
  487. // | _|| ' \ _| '_/ -_) -_|_-<
  488. // |___|_||_\__|_| \___\___/__/
  489. function filterEntree(t){
  490. for (var n = 0; n < _nodes.length; n++) {
  491. if(_nodes[n].entrees.indexOf(t) == -1){
  492. _nodes[n].setAside();
  493. }else{
  494. _nodes[n].setCenteredOnEntree(t);
  495. }
  496. }
  497. };
  498. function scrambleCollection(){
  499. for (var i = 0; i < _nodes.length; i++) {
  500. _nodes[i].scramble();
  501. }
  502. setTimeout(stopScrambling, 5000);
  503. };
  504. function stopScrambling(){
  505. for (var i = 0; i < _nodes.length; i++) {
  506. _nodes[i].stopScrambling();
  507. }
  508. };
  509. // _ _ _ _
  510. // /_\ _ _| |_(_)__| |___ ___
  511. // / _ \| '_| _| / _| / -_|_-<
  512. // /_/ \_\_| \__|_\__|_\___/__/
  513. function initArtilesLink(){
  514. // add "articles link to blockentrees"
  515. _$articles_link = $('<a>')
  516. .html('Articles')
  517. .attr("href", "#articles")
  518. .addClass('articles-link')
  519. .on('click', onCLickedOnArticles);
  520. $('.item-list ul',_$entrees_block).append(
  521. $('<li>').append(
  522. $('<span class="oblique-wrapper">').append(_$articles_link)
  523. )
  524. );
  525. };
  526. function onCLickedOnArticles(e){
  527. e.preventDefault();
  528. $(this).toggleClass('is-active');
  529. if($(this).is('.is-active')){
  530. filterArticles();
  531. }else{
  532. resetArticlesFilter();
  533. }
  534. // _$canvas.trigger({
  535. // 'type':'corpus-cliqued-on-articles'
  536. // });
  537. return false;
  538. };
  539. function filterArticles(){
  540. console.log('filterArticles');
  541. for (var i = 0; i < _no_articles_nodes.length; i++) {
  542. _no_articles_nodes[i].fade();
  543. }
  544. };
  545. function resetArticlesFilter(){
  546. console.log('resetArticlesFilter');
  547. for (var i = 0; i < _no_articles_nodes.length; i++) {
  548. _no_articles_nodes[i].unFade();
  549. }
  550. };
  551. // ______ __
  552. // / ____/ _____ ____ / /______
  553. // / __/ | | / / _ \/ __ \/ __/ ___/
  554. // / /___ | |/ / __/ / / / /_(__ )
  555. // /_____/ |___/\___/_/ /_/\__/____/
  556. function initEvents(){
  557. _$canvas
  558. .on('mousemove', function(event) {
  559. event.preventDefault();
  560. _m_pos.x = event.originalEvent.clientX;
  561. _m_pos.y = event.originalEvent.clientY;
  562. })
  563. .on('mouseenter', function(event){
  564. // console.log('onMouseIN');
  565. _mouse_in = true;
  566. })
  567. .on('mouseout', function(event){
  568. // console.log('onMouseOUT');
  569. _mouse_in = false;
  570. _node_pop_up.removeNode();
  571. })
  572. .on('click', function(event) {
  573. if(event.target.tagName != "A" && event.target.tagName != "INPUT"){
  574. // console.log("Corpus : click");
  575. event.preventDefault();
  576. if(_node_hover_id != -1){
  577. // console.log("corpus : click on node", _nodes[_node_hover_id]);
  578. var event = {
  579. 'type':'corpus-cliked-on-node',
  580. 'target_node':{
  581. 'id':_node_hover_id,
  582. 'nid':_nodes[_node_hover_id].nid,
  583. 'audio_url':_nodes[_node_hover_id].son_url
  584. },
  585. };
  586. _$canvas.trigger(event);
  587. openNode(_node_hover_id);
  588. }else{
  589. // console.log('corpus : click on map');
  590. _$canvas.trigger('corpus-cliked-on-map');
  591. }
  592. }
  593. })
  594. .on('audio-node-closed', function(e){
  595. closeNode();
  596. });
  597. _$entrees_block_termlinks.on('click', function(event) {
  598. event.preventDefault();
  599. var tid = $(this).attr('tid');
  600. var $li = $(this).parents('li');
  601. if(!$li.is('.opened')){
  602. _$entrees_block_termlinks.parents('li').removeClass('opened');
  603. $li.addClass('opened');
  604. filterEntree(tid);
  605. _$body.trigger({'type':'open_entree', 'tid':tid});
  606. }else{
  607. $li.removeClass('opened');
  608. scrambleCollection();
  609. _$body.trigger({'type':'close_entree', 'tid':tid});
  610. }
  611. return false;
  612. });
  613. // $('body').trigger({
  614. // 'type':'chutier-action-done',
  615. // 'action_done':data.action_done,
  616. // 'target_id':$link.attr('target_id'),
  617. // });
  618. _$body.on('chutier-action-done', function(e) {
  619. _nodes_by_nid[e.target_id].chutier_action = e.new_action;
  620. });
  621. };
  622. // _ _ _ ___ _ _
  623. // | \| |___ __| |___| _ \___ _ __| | | |_ __
  624. // | .` / _ \/ _` / -_) _/ _ \ '_ \ |_| | '_ \
  625. // |_|\_\___/\__,_\___|_| \___/ .__/\___/| .__/
  626. // |_| |_|
  627. function initNodePopup(){
  628. _node_pop_up = new NodePopUp();
  629. };
  630. function NodePopUp(){
  631. this.visible = false;
  632. this.node;
  633. this.$dom = $('<div>')
  634. .addClass('node-popup')
  635. .attr('pos', 'top-right')
  636. .appendTo('body');
  637. this.$content = $('<div>').addClass('inner').appendTo(this.$dom);
  638. if (typeof NodePopUp.initialized == "undefined") {
  639. NodePopUp.prototype.setNode = function(n){
  640. // console.log('NodePopUp setNode()');
  641. this.node = n;
  642. // positioning NodePopUp regarding node position
  643. this.setPositioning();
  644. // update NodePopUp content
  645. this.setContent();
  646. };
  647. NodePopUp.prototype.setPositioning = function(){
  648. switch(true){
  649. case this.node.x > this.node.wall_limits.right-350 && this.node.y < this.node.wall_limits.top+200:
  650. this.$dom.attr('pos', 'bottom-left');
  651. break;
  652. case this.node.x > this.node.wall_limits.right-350:
  653. this.$dom.attr('pos', 'top-left');
  654. break;
  655. case this.node.y < this.node.wall_limits.top+200:
  656. this.$dom.attr('pos', 'bottom-right');
  657. break;
  658. default:
  659. this.$dom.attr('pos', 'top-right');
  660. }
  661. };
  662. NodePopUp.prototype.setContent = function(){
  663. // console.log(this.node);
  664. this.$content.html('');
  665. var $entrees = $('<div>').addClass('entrees');
  666. for (var i = 0; i < this.node.entrees.length; i++) {
  667. var tid = this.node.entrees[i];
  668. $entrees.append($('<span>').addClass('entree').attr('tid', tid));
  669. }
  670. var $chutier_action = $('<span>').addClass('chutier-icon').attr('action', this.node.chutier_action);
  671. this.$content
  672. .append($entrees)
  673. .append('<h2 class="title">'+this.node.title+'</h2>')
  674. .append('<section class="description">'+this.node.description+'</section>')
  675. .append($chutier_action);
  676. // TODO: favoris marker
  677. };
  678. NodePopUp.prototype.removeNode = function(){
  679. // console.log('NodePopUp removeNode()');
  680. this.node = false;
  681. };
  682. NodePopUp.prototype.draw = function(){
  683. if(this.node){
  684. this.$dom.css({
  685. 'display':"block",
  686. 'left':this.node.x+"px",
  687. 'top':this.node.y+"px",
  688. });
  689. }else{
  690. this.$dom.css({
  691. 'display':"none",
  692. });
  693. }
  694. };
  695. NodePopUp.initialized = true;
  696. }
  697. }
  698. // ____ __
  699. // / __ \___ ____ ____/ /__ _____
  700. // / /_/ / _ \/ __ \/ __ / _ \/ ___/
  701. // / _, _/ __/ / / / /_/ / __/ /
  702. // /_/ |_|\___/_/ /_/\__,_/\___/_/
  703. function render(){
  704. _ctx.clearRect(0, 0, _canvas.width, _canvas.height);
  705. checkParticulesCollisions();
  706. for (var i = 0; i < _nodes.length; i++) {
  707. _nodes[i].onUpdate();
  708. }
  709. _node_pop_up.draw();
  710. if(_node_hover_id != -1){
  711. _canvas.style.cursor = 'pointer';
  712. highlightEntries();
  713. // _node_pop_up.visible = true;
  714. }else{
  715. _canvas.style.cursor = 'auto';
  716. _$entrees_block_termlinks.removeClass('highlighted');
  717. // _node_pop_up.visible = false;
  718. }
  719. };
  720. // _ _ _ _ _ _ _ _ ___ _ _
  721. // | || (_)__ _| |_ | |_(_)__ _| |_| |_| __|_ _| |_ _ _(_)___ ___
  722. // | __ | / _` | ' \| / / / _` | ' \ _| _|| ' \ _| '_| / -_|_-<
  723. // |_||_|_\__, |_||_|_\_\_\__, |_||_\__|___|_||_\__|_| |_\___/__/
  724. // |___/ |___/
  725. function highlightEntries(){
  726. _$entrees_block_termlinks.removeClass('highlighted');
  727. var entree;
  728. for (var i = 0; i < _nodes[_node_hover_id].entrees.length; i++) {
  729. entree = _nodes[_node_hover_id].entrees[i];
  730. _$entrees_block_termlinks.filter(function(){
  731. return $(this).attr('tid') == entree;
  732. }).addClass('highlighted');
  733. }
  734. }
  735. // ___ _ _ _ _
  736. // / __| |_ __ _ _ _| |_ /_\ _ _ (_)_ __ ___
  737. // \__ \ _/ _` | '_| _|/ _ \| ' \| | ' \/ -_)
  738. // |___/\__\__,_|_| \__/_/ \_\_||_|_|_|_|_\___|
  739. function startAnime(){
  740. _physics.onUpdate(render);
  741. _physics.play()
  742. $('body').trigger('corpus-map-ready');
  743. };
  744. init();
  745. }
  746. $(document).ready(function($) {
  747. var edlpcorpus = new EdlpCorpus();
  748. });
  749. })(jQuery);