/** * @Author: Bachir Soussi Chiadmi * @Date: 18-12-2017 * @Email: bachir@figureslibres.io * @Filename: corpus.js * @Last modified by: bach * @Last modified time: 20-12-2017 * @License: GPL-V3 */ // JS performance improvement http://archive.oreilly.com/pub/a/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html /** * depends on : * physics.js : http://jonobr1.com/Physics/# */ (function($, Drupal, drupalSettings) { EdlpCorpus = function(){ var _activated = true; var _$body = $('body'); var _$container = _$body; var _$canvas = $('').appendTo(_$container); var _canvas = _$canvas[0]; var _ctx = _canvas.getContext('2d'); var _dpi = window.devicePixelRatio; var _is_expo = $('body').hasClass('domain-expo-encyclopediedelaparole-org'); var _scene_props = { width:window.innerWidth, height:window.innerHeight, // 'margin_top':90, // with red border on head 'margin_top': _is_expo ? 0 : 75, // without red border on head // 'margin_top':0, 'margin_right':0, 'margin_bottom': _is_expo ? 0 : 65, // 'margin_bottom':0, 'margin_left':0 }; var _evolution_zone = { left:_scene_props.width/4, right:_scene_props.width - _scene_props.width/4, center:_scene_props.width/2, }; var _physics = new Physics(); var _nodes = []; var _articles_nodes = []; var _no_articles_nodes = []; // var _articles_filter_on = false; var _nodes_by_entries = {}; var _nodes_by_nid = {}; var _nodes_Nid_Id = {}; var _nodes_centered = []; var _nodes_centered_attractions = []; var _loaded = false; var _playlist = []; var _p_velocity_factor = 0.5; var _mouse_in = true; var _m_pos = {x:0, y:0}; var _node_hover_id = -1; var _node_opened_id = -1; var _$entrees_block = $('#block-edlpentreesblock'); var _$entrees_block_termlinks = $('a.term-link', _$entrees_block); var _$articles_link; var _node_pop_up; // Colors depend on drupalSettings loaded by edlp_corpus.module var _settings = drupalSettings.edlp_corpus; var _ecolors = _settings.colors; // Physics var _attracter; var check_parts_colid_frq = 2; var check_parts_colid_tick = 1; // ____ _ __ // / _/___ (_) /______ // / // __ \/ / __/ ___/ // _/ // / / / / /_(__ ) // /___/_/ /_/_/\__/____/ function init(){ console.log("Corpus init()"); initCanvas(); if(_activated){ loadCorpus(); }else{ _$canvas.addClass('de-activated'); } }; // ___ // / __|__ _ _ ___ ____ _ ___ // | (__/ _` | ' \ V / _` (_-< // \___\__,_|_||_\_/\__,_/__/ function initCanvas(){ // resize the canvas to fill browser window dynamically window.addEventListener('resize', onResizeCanvas, false); onResizeCanvas(); }; function onResizeCanvas() { // _dpi = 2; _scene_props.width = window.innerWidth; _scene_props.height = window.innerHeight; _canvas.style.width = _scene_props.width+'px'; _canvas.style.height = _scene_props.height+'px'; _canvas.width = _scene_props.width*_dpi; _canvas.height = _scene_props.height*_dpi; _ctx.scale(_dpi, _dpi); moveEvolutionZone(); if(_loaded){ for (var i = 0; i < _nodes.length; i++) { _nodes[i].onResizeCanvas(); } // move _attracter and _repulser to their right places again // moveEvolutionZone() will trigger resizePhysics() // resizePhysics(); } }; // ___ // / __|___ _ _ _ __ _ _ ___ // | (__/ _ \ '_| '_ \ || (_-< // \___\___/_| | .__/\_,_/__/ // |_| function loadCorpus(){ // console.log('drupalSettings',drupalSettings); // console.log('window.location', window.location); // var path = window.location.origin + drupalSettings.basepath + "edlp/corpus"; var ajax_path = _settings.load_corpus_ajax_url; var path = window.location.origin + Drupal.url(ajax_path); $.getJSON(path, {}) .done(function(data){ onCorpusLoaded(data); }) .fail(function(jqxhr, textStatus, error){ onCorpusLoadError(jqxhr, textStatus, error); }); }; function onCorpusLoadError(jqxhr, textStatus, error){ console.warn('corpus load failed', jqxhr.responseText); }; function onCorpusLoaded(data){ console.log('corpus loaded : data', data); // console.log('first node', data.nodes[0]); // buildParticles(data.nodes); initPhysics(); buildNodes(data.nodes); initArtilesLink(); initNodePopup(); initEvents(); checkPreOpenedEntry(); startAnime(); _loaded = true; }; // ___ _ _ // | _ \ |_ _ _ __(_)__ ___ // | _/ ' \ || (_-< / _(_-< // |_| |_||_\_, /__/_\__/__/ // |__/ function initPhysics(){ _attracter = _physics.makeParticle(1000); _attracter.fixed = true; // move _attracter on window resize resizePhysics(); }; function resizePhysics(){ // attracters if(typeof _attracter != 'undefined'){ _attracter.position = {x:_evolution_zone.center, y:_scene_props.height/2}; } }; // _ _ _ // | \| |___ __| |___ ___ // | .` / _ \/ _` / -_|_-< // |_|\_\___/\__,_\___/__/ function buildNodes(nodes){ // console.log("buildNodes", nodes); var d; for (var i in nodes) { d = i < 1 ? true : false; // _nodes.push(new Node(i,nodes[i],d)); new Node(i,nodes[i],d); _playlist.push({ 'id':i, 'nid':nodes[i].nid, 'audio_url':nodes[i].audio_url, 'document_url':nodes[i].document_url, }); } }; function Node(i,node,d){ this.id = i; for(key in node) this[key] = node[key]; // record the node in different lists _nodes.push(this); _nodes_by_nid[this.nid] = this; _nodes_Nid_Id[this.nid] = this.id; if(this.has_article == 1){ _articles_nodes.push(this); }else{ _no_articles_nodes.push(this); } for (var j = 0; j < this.entrees.length; j++) { if(typeof _nodes_by_entries[this.entrees[j]] == 'undefined') _nodes_by_entries[this.entrees[j]] = []; _nodes_by_entries[this.entrees[j]].push(this); } this.debug = d; this.mass = Math.max(1, this.entrees.length); //1; this.velocity_threshold = 0.01; // define radius regarding entries length switch(true){ case this.entrees.length > 3: this.r = 8;//10; break; case this.entrees.length > 1 && this.entrees.length <= 3: this.r = 5;//7; break; default: this.r = 3;//4; break; } this.d = this.r*2; this.e_color = 'e_col_'+this.entrees[Math.floor(Math.random(this.entrees.length))]; // pre-rendering node virtual canvas this.canvas = document.createElement('canvas'); this.canvas_ctx = this.canvas.getContext('2d'); this.line_width = 1; this.w = this.r*2+this.line_width*2; this.w_2 = this.w/2; this.canvas.width = this.w; this.canvas.height = this.w; this.canvas_ctx.fillStyle = 'rgb(255,255,255)'; this.canvas_ctx.lineWidth = this.line_width; this.wall_bouncing_elasticity = 0.75; // node states this.hover = false; this.opened = false; this.faded = false; this.center = false; this.aside = false; this.scrambling = false; // prototypes if (typeof Node.initialized == "undefined") { Node.prototype.init = function(){ this.calcWallLimits(); this.x = this.wall_limits.left + Math.random()*(this.wall_limits.right - this.wall_limits.left); this.y = this.wall_limits.top + Math.random()*(this.wall_limits.bottom - this.wall_limits.top); this.ori_pos = {x:this.x,y:this.y}; // TODO: don't forget to move ori_pos on window resize //this.drawSprite(); this.initPhysics(); }; // Node.prototype.drawSprite = function(){ // _ctx.clearRect(0, 0, this.w, this.w); // // this.canvas_ctx.beginPath(); // // white background // this.canvas_ctx.fillRect(0,0,this.w,this.w); // // this.canvas_ctx.globalAlpha = this.faded ? 0.15 : 1; // // if(this.opened){ // // carre plein // // this.canvas_ctx.lineWidth = '1px'; // // this.canvas_ctx.strokeStyle = 'rgb(255,0,0)'; // // this.canvas_ctx.strokeRect(this.x - this.r-3,this.y - this.r-3,this.r*2+6,this.r*2+6); // // ou carre contour // this.canvas_ctx.save(); // save the normal context state (fill white) // this.canvas_ctx.fillStyle = _ecolors[this.e_color]; // this.canvas_ctx.fillRect(this.line_width,this.line_width,this.d,this.d); // this.canvas_ctx.restore(); // restore the normal context state (fill white) // } // // else{ // // // carre plein // // // this.canvas_ctx.fillStyle = _ecolors[this.e_color]; // // // this.canvas_ctx.fillRect(this.x - this.r,this.y - this.r,this.d,this.d); // // // ou carre contour // // this.canvas_ctx.fillRect(this.line_width,this.line_width,this.d,this.d); // // } // this.canvas_ctx.strokeStyle = _ecolors[this.e_color]; // this.canvas_ctx.strokeRect(this.line_width,this.line_width,this.d,this.d); // // this.canvas_ctx.globalAlpha = 1; // this.canvas_ctx.closePath(); // }; Node.prototype.initPhysics = function(){ // particule this.p = _physics.makeParticle(this.mass, this.x, this.y); this.p.velocity = new Physics.Vector((Math.random()-0.5)*_p_velocity_factor, (Math.random()-0.5)*_p_velocity_factor); // origin position particule this.ori_p = _physics.makeParticle(1000, this.ori_pos.x, this.ori_pos.y); this.ori_p.fixed = true; // TODO: don't forget to move ori_p on window resize this.ori_p_attract = _physics.makeAttraction(this.ori_p, this.p, 1000, _scene_props.width*2); this.ori_p_attract.on = false; // attracter this.attract = _physics.makeAttraction(_attracter, this.p, 1000, _scene_props.width*2); this.attract.on = false; }; Node.prototype.calcWallLimits = function(){ this.wall_limits = { top: _scene_props.margin_top +this.r, right: _scene_props.width -_scene_props.margin_right -this.r, bottom: _scene_props.height -_scene_props.margin_bottom -this.r, left: _scene_props.margin_left +this.r } }; Node.prototype.onResizeCanvas = function(){ this.calcWallLimits(); // TODO: scramble only if not aside or centered this.shuffleOriP(); }; Node.prototype.shuffleOriP = function(){ this.ori_pos.x = this.wall_limits.left + Math.random()*(this.wall_limits.right - this.wall_limits.left); this.ori_pos.y = this.wall_limits.top + Math.random()*(this.wall_limits.bottom - this.wall_limits.top); this.scramble(); }; Node.prototype.onUpdate = function(){ // this.p.velocity.multiplyScalar(0.99); if(this.hover || this.opened){ this.p.fixed = true; }else{ this.p.fixed = false; if(this.center) this.limitEvolutionZone(); // if(!this.p.resting()){ // this.checkVelocityThreshold(); this.checkWallBouncing(); this.updatePos(); if(this.scrambling){ this.checkOriPDist(); } // } } if(_mouse_in && !this.aside && !this.faded) this.checkMouse(); // this.move(); this.redraw(); }; Node.prototype.checkVelocityThreshold = function(){ if(!this.centered || !this.aside){ if (Math.abs(this.p.velocity.x) < this.velocity_threshold && Math.abs(this.p.velocity.y) < this.velocity_threshold){ this.p.velocity.multiplyScalar(0); // this.p.makeFixed(); } } }; Node.prototype.checkWallBouncing = function(){ switch(true){ case this.x < this.wall_limits.left && this.p.velocity.x < 0: this.p.position.x = this.wall_limits.left; this.p.velocity .multiplyScalarXY(-1, 1) .multiplyScalar(this.wall_bouncing_elasticity); break; case this.x > this.wall_limits.right && this.p.velocity.x > 0: this.p.position.x = this.wall_limits.right; this.p.velocity .multiplyScalarXY(-1, 1) .multiplyScalar(this.wall_bouncing_elasticity); break; case this.y < this.wall_limits.top && this.p.velocity.y < 0 : this.p.position.y = this.wall_limits.top; this.p.velocity .multiplyScalarXY(1,-1) .multiplyScalar(this.wall_bouncing_elasticity); break; case this.y > this.wall_limits.bottom && this.p.velocity.y > 0 : this.p.position.y = this.wall_limits.bottom; this.p.velocity .multiplyScalarXY(1,-1) .multiplyScalar(this.wall_bouncing_elasticity); break; } }; Node.prototype.updatePos = function(){ this.x = this.p.position.x; this.y = this.p.position.y; }; Node.prototype.checkMouse = function(){ if( _m_pos.x > this.x - this.r && _m_pos.x < this.x + this.r && _m_pos.y > this.y - this.r && _m_pos.y < this.y + this.r){ if(_node_hover_id == -1 || _node_hover_id !== this.id){ // console.log("Node hover", this.id); this.setHover(); } }else{ this.unsetHover(); } }; Node.prototype.setHover = function(){ this.hover = true; _node_hover_id = this.id; _node_pop_up.setNode(this); }; Node.prototype.unsetHover = function(){ this.hover = false; if (_node_hover_id == this.id) { _node_hover_id = -1; _node_pop_up.removeNode(); } }; Node.prototype.open = function(){ this.opened = true; _node_opened_id = this.id; //this.drawSprite(); }; Node.prototype.close = function(){ this.opened = false; //this.drawSprite(); }; Node.prototype.fade = function(){ this.faded = true; //this.drawSprite(); }; Node.prototype.unFade = function(){ this.faded = false; //this.drawSprite(); }; Node.prototype.setCenteredOnEntree = function(tid){ this.e_color = 'e_col_'+tid; this.setCentered(); }; Node.prototype.setCentered = function(){ this.center = true; this.stopScrambling(); this.unsetAside(); this.attract.on = true; //this.drawSprite(); } Node.prototype.unsetCentered = function(){ this.center = false; this.attract.on = false; } Node.prototype.limitEvolutionZone = function(){ // smouthly slow down node near center // if(this.id == 1) // console.log('this.p.velocity', this.p.velocity); this.dist_to_attracter = this.p.distanceTo(_attracter); if( this.dist_to_attracter < _scene_props.width/4){ if( this.p.velocity.length() > 0.4 ){ this.p.velocity.multiplyScalar(0.99); // 0.995 } } // limit evolution zone // if( Math.abs(_attracter.position.x - this.x) > _scene_props.width/4 // || Math.abs(_attracter.position.y - this.y) > _scene_props.height/4){ if( this.x < _evolution_zone.left || this.x > _evolution_zone.right || Math.abs(_attracter.position.y - this.y) > _scene_props.height/4){ this.attract.on = true; }else{ this.attract.on = false; } } Node.prototype.setAside = function(){ this.aside = true; // this.fade(); this.stopScrambling(); this.unsetCentered(); this.ori_p.position.x = this.x < _scene_props.width /2 ? this.wall_limits.left : this.wall_limits.right; this.ori_p_attract.on = true; this.wall_bouncing_elasticity = 0.15; } Node.prototype.unsetAside = function(){ // console.log('unsetAside'); this.aside = false; this.ori_p_attract.on = false; this.ori_p.position.x = this.ori_pos.x; this.wall_bouncing_elasticity = 0.75; // this.unFade(); } Node.prototype.resolveNormalPos = function(){ // console.log("resolveNormalPos"); switch(true){ case this.center: this.unsetCentered(); break; case this.aside: this.unsetAside(); break; } }; Node.prototype.scramble = function(){ this.scrambling = true; this.unsetCentered(); this.unsetAside(); this.ori_p.position.x = this.ori_pos.x; this.ori_p.position.y = this.ori_pos.y; this.ori_p_attract.on = true; } Node.prototype.checkOriPDist = function(){ if(this.p.distanceTo(this.ori_p) < 50){ this.stopScrambling(); } }; Node.prototype.stopScrambling = function(){ this.scrambling = false; this.ori_p_attract.on = false; // this.scramble_TL.on = false; // this.scramble_TR.on = false; // this.scramble_BR.on = false; // this.scramble_BL.on = false; // this.scramble_CR.on = false; // this.scramble_CL.on = false; } Node.prototype.move = function(){ // just draw the virtual node canvas into the main scene canvas at the right position _ctx.drawImage(this.canvas, this.x-this.w_2, this.y-this.w_2); }; Node.prototype.redraw = function(){ _ctx.beginPath(); // white background _ctx.fillStyle = 'rgb(255,255,255)'; _ctx.fillRect(this.x-this.r,this.y-this.r,this.d,this.d); _ctx.globalAlpha = this.faded ? 0.15 : 1; if(this.opened){ // carre plein // _ctx.lineWidth = '1px'; // _ctx.strokeStyle = 'rgb(255,0,0)'; // _ctx.strokeRect(this.x - this.r-3,this.y - this.r-3,this.r*2+6,this.r*2+6); // ou carre contour // _ctx.save(); // save the normal context state (fill white) _ctx.fillStyle = _ecolors[this.e_color]; _ctx.fillRect(this.x-this.r,this.y-this.r,this.d,this.d); // _ctx.restore(); // restore the normal context state (fill white) } // else{ // // carre plein // // _ctx.fillStyle = _ecolors[this.e_color]; // // _ctx.fillRect(this.x - this.r,this.y - this.r,this.d,this.d); // // ou carre contour // _ctx.fillRect(this.line_width,this.line_width,this.d,this.d); // } _ctx.strokeStyle = _ecolors[this.e_color]; _ctx.strokeRect(this.x-this.r,this.y-this.r,this.d,this.d); // _ctx.globalAlpha = 1; _ctx.closePath(); }; Node.initialized = true; } this.init(); }; // 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 function checkParticulesCollisions(){ // do not run particule collision every frames if(check_parts_colid_tick < check_parts_colid_frq){ check_parts_colid_tick++; return; } check_parts_colid_tick = 1; // pre create vars to save memory; var na,nb, ma,mb, w,h,dx,dy, makeup, newVelX1, newVelY1, newVelX2, newVelY2, Smamb; // , angle; // colisions between _particules for (var n = 0, l = _nodes.length; n < l; n++) { na = _nodes[n]; // avoid colliding for scrambling nodes // avoid colliding for aside nodes // avoid colliding for centered nodes if(na.scrambling || na.aside ) continue; //|| na.center ma = na.p.mass; for (var q = n+1; q < l; q++) { nb = _nodes[q]; // avoid impact between center and aside particules // if((na.center && nb.aside) || (na.aside && nb.center)) // and between aside particules if(nb.aside) continue; // avoid impact between two centered particulses that comes to the center if(na.center && nb.center){ if(Math.min(na.p.distanceTo(_attracter), nb.p.distanceTo(_attracter)) > 300){ if( Math.random()>0.3 ) continue; } } w = h = (na.r+nb.r); // if(!na.aside && !nb.aside){ w = h += 4; // add a saftey zone around squares eccept for aside squares // } // if both dx and dy are inferior to w & h so squares are colliding (overlapping) // if( Math.abs(dx) <= w && Math.abs(dy) <= h){ console.log('colliding'); } // else not so skip // if( Math.abs(dx) > w || Math.abs(dy) > h) continue; dx = na.p.position.x - nb.p.position.x; if( Math.abs(dx) > w ) continue; dy = na.p.position.y - nb.p.position.y; if(Math.abs(dy) > h) continue mb = nb.p.mass; Smamb = ma+mb; if(Math.abs(dx) < Math.abs(dy)){ // vertical collision makeup = (h - Math.abs(dy))/2; if(dy > 0){ // a is upper than b na.p.position.y += makeup; nb.p.position.y -= makeup; }else{ // b is upper than a na.p.position.y -= makeup; nb.p.position.y += makeup; } // bounce // https://en.wikipedia.org/wiki/Elastic_collision#One-dimensional_Newtonian newVelY1 = (ma-mb)/Smamb*na.p.velocity.y+2*mb/Smamb*nb.p.velocity.y; newVelY2 = (mb-ma)/Smamb*nb.p.velocity.y+2*ma/Smamb*na.p.velocity.y; na.p.velocity.y = newVelY1; nb.p.velocity.y = newVelY2; }else{ // horizontal collision makeup = (w - Math.abs(dx))/2; if(dx > 0){ // a is at left of b na.p.position.x += makeup; nb.p.position.x -= makeup; }else{ // b is at left of a na.p.position.x -= makeup; nb.p.position.x += makeup; } // bounce // https://en.wikipedia.org/wiki/Elastic_collision#One-dimensional_Newtonian newVelX1 = (ma-mb)/Smamb*na.p.velocity.x+2*mb/Smamb*nb.p.velocity.x; newVelX2 = (mb-ma)/Smamb*nb.p.velocity.x+2*ma/Smamb*na.p.velocity.x; na.p.velocity.x = newVelX1; nb.p.velocity.x = newVelX2; } // slow down particule on impact // na.p.velocity.multiplyScalar(na.center && na.p.velocity.length() < 1 ? 1.1 : 0.90); // nb.p.velocity.multiplyScalar(nb.center && nb.p.velocity.length() < 1 ? 1.1 : 0.90); na.p.velocity.multiplyScalar(0.90); nb.p.velocity.multiplyScalar(0.90); } } }; // show opened audio node function openNodeByNid(nid){ // console.log('Corpus openNode()', nid); closeNode(); if(typeof _nodes_Nid_Id[nid] != 'undefined'){ // console.log('node exists'); _node_opened_id = _nodes_Nid_Id[nid]; _nodes[_nodes_Nid_Id[nid]].open(); } } function closeNode(){ if(_node_opened_id != -1){ // if(typeof _nodes[_node_opened_id] !== 'undefined'){ _nodes[_node_opened_id].close(); // } _node_opened_id = -1; } } function createNodesRepulsions(){ // how to delete all these attractions before creates new once //console.log('_nodes_centered', _nodes_centered); purgeNodesRepulsions(); for (var n = 0; n < _nodes_centered.length; n++) { for (var q = n+1; q < _nodes_centered.length; q++) { _physics.makeAttraction(_nodes_centered[n].p, _nodes_centered[q].p, -0.4, 10); } } }; function purgeNodesRepulsions(){ // console.log('_physics.attractions.length', _physics.attractions.length); for (var a = _physics.attractions.length-1; a >= 0; a--) { // assuming that only nodes repulsions have constant < 1 // and are all at the end of array if(Math.abs(_physics.attractions[a].constant) < 1){ _physics.attractions.splice(a,1); }else{ break; } } // console.log('_physics.attractions.length', _physics.attractions.length); }; // ___ _ _ _ ____ // | __|_ _____| |_ _| |_(_)___ _ _ |_ /___ _ _ ___ // | _|\ V / _ \ | || | _| / _ \ ' \ / // _ \ ' \/ -_) // |___|\_/\___/_|\_,_|\__|_\___/_||_| /___\___/_||_\___| function moveEvolutionZone(l, r){ var left = l || 0; var right = r || 0; console.log("moveEvolutionZone",left,right); console.log("_scene_props", _scene_props); _evolution_zone.left = left == 0 ? left+20 : Math.max(_scene_props.width/5, left+20); _evolution_zone.right = right == 0 ? _scene_props.width-right+20 : Math.min(_scene_props.width - _scene_props.width/5, _scene_props.width-right+20); _evolution_zone.center = _evolution_zone.left + (_evolution_zone.right - _evolution_zone.left)/2; console.log("moveEvolutionZone",_evolution_zone); // move _attracter to the center of the zone resizePhysics(); } // ___ _ ___ _ _ _ _ // | _ \__ _ _ _ __| |___ _ __ | _ \ |__ _ _ _| (_)__| |_ // | / _` | ' \/ _` / _ \ ' \ | _/ / _` | || | | (_-< _| // |_|_\__,_|_||_\__,_\___/_|_|_| |_| |_\__,_|\_, |_|_/__/\__| // |__/ function updateRandomPlaylist(p){ _$canvas.trigger({ type:'update-random-playlist', playlist:p }) }; // ___ _ // | __|_ _| |_ _ _ ___ ___ ___ // | _|| ' \ _| '_/ -_) -_|_-< // |___|_||_\__|_| \___\___/__/ function toggleEntree(tid, bubbling){ var $link = _$entrees_block_termlinks.filter('[tid="'+tid+'"]'); var $li = $link.parents('li'); var sys_path = $link.attr('data-drupal-link-system-path'); var url = $link.attr('href'); var title = $link.text(); if(!$li.is('.opened')){ _$entrees_block_termlinks.parents('li').removeClass('opened'); $li.addClass('opened'); $li.parents('.item-list').addClass('opened') filterEntree(tid); if(bubbling){ _$body.trigger({ 'type':'open_entree', 'tid':tid, 'url':url, 'sys_path':sys_path, 'title':title }); } // bubbling is true only when event is a real click on entree link }else if(bubbling){ $li.removeClass('opened'); $li.parents('.item-list').removeClass('opened') scrambleCollection(); _$body.trigger({'type':'close_entree', 'tid':tid}); } }; function filterEntree(t){ // shutDownArticles(); _nodes_centered = []; for (var n = 0; n < _nodes.length; n++) { if(_nodes[n].entrees.indexOf(t) == -1){ _nodes[n].setAside(); }else{ _nodes[n].setCenteredOnEntree(t); // record centered nodes for inter node repulsions _nodes_centered.push(_nodes[n]); } } updateRandomPlaylist(_nodes_centered); createNodesRepulsions(); }; function highlightEntries(){ _$entrees_block_termlinks .parents('li').removeClass('highlighted') .parents('.item-list').removeClass('highlighted'); var id = -1; if(_node_hover_id != -1){ id = _node_hover_id; }else if(_node_opened_id != -1){ id = _node_opened_id; } var entree; if(id != -1){ for (var i = 0; i < _nodes[id].entrees.length; i++) { entree = _nodes[id].entrees[i]; _$entrees_block_termlinks.filter(function(){ return $(this).attr('tid') == entree; }).parents('li').addClass('highlighted') .parents('.item-list').addClass('highlighted'); } } }; // ___ _ // / __| ___ __ _ _ _ __| |_ // \__ \/ -_) _` | '_/ _| ' \ // |___/\___\__,_|_| \__|_||_| // and ajax modal content filtering function filterByNids(nids){ // shutDownArticles(); _nodes_centered = []; for (var n = 0; n < _nodes.length; n++) { if(nids.indexOf(_nodes[n].nid) == -1){ _nodes[n].setAside(); }else{ _nodes[n].setCentered(); // record centered nodes for inter node repulsions _nodes_centered.push(_nodes[n]); } } updateRandomPlaylist(_nodes_centered); createNodesRepulsions(); }; // ___ _ _ _ // / __| __ _ _ __ _ _ __ | |__| (_)_ _ __ _ // \__ \/ _| '_/ _` | ' \| '_ \ | | ' \/ _` | // |___/\__|_| \__,_|_|_|_|_.__/_|_|_||_\__, | // |___/ // function resolveNormalPosAllNodes(){ // console.log('resolveNormalPosAllNodes'); // for (var i = 0; i < _nodes.length; i++) { // _nodes[i].resolveNormalPos(); // } // }; function scrambleCollection(){ console.log('Corpus scrambleCollection'); for (var i = 0; i < _nodes.length; i++) { _nodes[i].scramble(); } updateRandomPlaylist(_playlist); // setTimeout(stopScrambling, 2000); // stopScrambling(); }; function closeAllEntries(){ _$entrees_block_termlinks.each(function(index, el) { if($(this).parents('li').is('.opened')){ $(this).trigger('click'); return false; } }); }; // _ _ _ _ // /_\ _ _| |_(_)__| |___ ___ // / _ \| '_| _| / _| / -_|_-< // /_/ \_\_| \__|_\__|_\___/__/ function initArtilesLink(){ // add "articles link to blockentrees" var href = window.location.origin + drupalSettings.path.baseUrl +_settings.articlesindex_url; _$articles_link = $('') .html('Articles') .attr("href", href) .attr("data-drupal-link-system-path", _settings.articlesindex_url) .addClass('articles-link ajax-link'); // main.js from template will load the index then trigger the filter here // .on('click', onCLickedOnArticles); $('.item-list ul',_$entrees_block).append( $('
  • ').append( $('').append(_$articles_link) ) ); }; // function onCLickedOnArticles(e){ // e.preventDefault(); // $(this).toggleClass('is-active'); // if($(this).is('.is-active')){ // activateArticlesFilter(); // closeAllEntries(); // }else{ // deactivateArticlesFilter(); // } // // _$canvas.trigger({ // // 'type':'corpus-cliqued-on-articles' // // }); // return false; // }; // function activateArticlesFilter(){ // //console.log('activateArticlesFilter'); // _articles_filter_on = true; // // OPTION 1 : just fade no article nodes // // for (var i = 0; i < _no_articles_nodes.length; i++) { // // _no_articles_nodes[i].fade(); // // } // // END OPTION 1 // // // OPTION 2 : center the articles nodes and aside others // closeAllEntries(); // _nodes_centered = []; // for (var i = 0; i < _articles_nodes.length; i++) { // _articles_nodes[i].setCentered(); // // record centered nodes for inter node repulsions // _nodes_centered.push(_articles_nodes[i]); // } // for (var i = 0; i < _no_articles_nodes.length; i++) { // _no_articles_nodes[i].setAside(); // } // // TODO: open an index of nodes with articles // // loadArticlesIndex(); // // END OPTION 2 // // updateRandomPlaylist(_articles_nodes); // if(typeof _paq !== 'undefined'){ // // trackEvent(category, action, [name], [value]) // _paq.push(['trackEvent', 'Corpus Articles', 'on']); // } // }; // function loadArticlesIndex(){ // var path = window.location.origin + drupalSettings.path.baseUrl +_settings.articlesindex_url+'/ajax'; // $.getJSON(path) // .done(function(data){ // onArticlesIndexLoaded(data); // }) // .fail(function(jqxhr, textStatus, error){ // onArticlesIndexLoadFail(jqxhr, textStatus, error); // }); // }; // // function onArticlesIndexLoaded(data){ // // insert index col // _$container.find('main[role="main"] .row').append(data.rendered); // // // trigger event // _$body.trigger({ // 'type':'articles-index-loaded', // 'results':data.results_nids // }); // }; // // function onArticlesIndexLoadFail(jqxhr, textStatus, error){ // console.warn('EdlpCorpus : articles index ajax load failed : '+error, jqxhr.responseText); // }; // function deactivateArticlesFilter(){ // //console.log('deactivateArticlesFilter'); // _articles_filter_on = false; // // // OPTION 1 : just fade no article nodes // // for (var i = 0; i < _no_articles_nodes.length; i++) { // // _no_articles_nodes[i].unFade(); // // } // // // OPTION 2 : centered / aside // scrambleCollection(); // // updateRandomPlaylist(_playlist); // if(typeof _paq !== 'undefined'){ // // trackEvent(category, action, [name], [value]) // _paq.push(['trackEvent', 'Corpus Articles', 'off']); // } // }; // function shutDownArticles(){ // shutdown articles if active // if(_$articles_link.is('.is-active')) // _$articles_link.trigger('click'); // }; // ___ _ // | __|_ _____ _ _| |_ ___ // | _|\ V / -_) ' \ _(_-< // |___|\_/\___|_||_\__/__/ function initEvents(){ console.log('Corpus, initEvents'); _$canvas .on('mousemove', function(event) { event.preventDefault(); _m_pos.x = event.originalEvent.clientX; _m_pos.y = event.originalEvent.clientY; }) .on('mouseenter', function(event){ // console.log('onMouseIN'); _mouse_in = true; }) .on('mouseout', function(event){ // console.log('onMouseOUT'); _mouse_in = false; _node_pop_up.removeNode(); }) .on('click', function(event) { if(event.target.tagName != "A" && event.target.tagName != "INPUT"){ // console.log("Corpus : click"); event.preventDefault(); if(_node_hover_id != -1){ // console.log("corpus : click on node", _nodes[_node_hover_id]); var event = { 'type':'corpus-cliked-on-node', 'target_node':_nodes[_node_hover_id], // 'article':_articles_filter_on }; _$canvas.trigger(event); // instead of directly opening the doc, create an event listener (e.g. : audio played from random) // openNode(_node_hover_id); }else{ // console.log('corpus : click on map'); _$canvas.trigger('corpus-cliked-on-map'); // shutDownArticles(); } } }) .on('mouseover-audio-link', function(e){ console.log("Corpus on mouseover-audio-link", e); // _node_hover_id = _nodes_Nid_Id[e.nid]; // _node_pop_up.setNode(_nodes_by_nid[e.nid]); _nodes_by_nid[e.nid].setHover(); }) .on('mouseout-audio-link', function(e){ console.log("Corpus on mouseover-audio-link", e); // _node_hover_id = -1; // _node_pop_up.removeNode(); _nodes_by_nid[e.nid].unsetHover(); }) .on('audio-node-opened', function(e){ // console.log('Corpus audio-node-opened', e); openNodeByNid(e.nid); }) .on('audio-node-closed', function(e){ closeNode(); }) .on('open-entree', function(e){ toggleEntree(e.tid); }) .on('close-all-entree', function(e){ closeAllEntries(); }) .on('scramble-collection', function(e){ console.log('scramble-collection', e); // resolveNormalPosAllNodes(); scrambleCollection(); }) .on('shuffle-collection', function(e){ console.log('shuffle-collection', e); onResizeCanvas(); }); _$entrees_block_termlinks.on('click', function(event) { // console.log('_$entrees_block_termlinks click', this); event.preventDefault(); toggleEntree($(this).attr('tid'), true); // var $link = $(this); // var tid = $link.attr('tid'); // var $li = $link.parents('li'); // var sys_path = $link.attr('data-drupal-link-system-path'); // var url = $link.attr('href'); // if(!$li.is('.opened')){ // _$entrees_block_termlinks.parents('li').removeClass('opened'); // $li.addClass('opened'); // toggleEntree(tid); // _$body.trigger({'type':'open_entree', 'tid':tid, 'url':url, 'sys_path':sys_path}); // }else{ // $li.removeClass('opened'); // scrambleCollection(); // _$body.trigger({'type':'close_entree', 'tid':tid}); // } return false; }); _$body .on('chutier-action-done', function(e) { _nodes_by_nid[e.target_id].chutier_action = e.new_action; }) .on('ajax-node-loaded-linked-documents', function(e){ console.log("Edlp Corpus, ajax-node-loaded-linked-documents",e.nids); // filter map's nodes filterByNids(e.nids); }) .on('search-results-loaded', function(e){ //console.log("Edlp Corpus, search-results-loaded",e.results); // filter map's nodes filterByNids(e.results); }) .on('search-closed', function(e){ scrambleCollection(); }) .on('new-content-not-entree-ajax-loaded', function(e){ // close all entries only if entry already opened // TODO: user the function close all entries ? // closeAllEntries(); not working, is closing also the ajax loaded content if(_$entrees_block_termlinks.parents('li.opened').length){ _$entrees_block_termlinks .parents('li').removeClass('opened') .parents('.item-list').removeClass('opened'); scrambleCollection(); } }) .on('visible-space-changed', function(e){ // limits are absolute distance from each side (not positions from left) moveEvolutionZone(e.left_limit, e.right_limit); }); }; function checkPreOpenedEntry(){ _$entrees_block.find('li.entree').each(function(index, el) { var $li = $(this); if($('a.is-active', $li).length){ $li.addClass('opened') .parents('.item-list').addClass('opened'); filterEntree($li.attr('tid')); return false; } }); }; // _ _ _ ___ _ _ // | \| |___ __| |___| _ \___ _ __| | | |_ __ // | .` / _ \/ _` / -_) _/ _ \ '_ \ |_| | '_ \ // |_|\_\___/\__,_\___|_| \___/ .__/\___/| .__/ // |_| |_| function initNodePopup(){ _node_pop_up = new NodePopUp(); }; function NodePopUp(){ this.visible = false; this.node; this.$dom = $('
    ') .addClass('node-popup') .attr('pos', 'top-right') .appendTo('body'); this.$content = $('
    ').addClass('inner').appendTo(this.$dom); if (typeof NodePopUp.initialized == "undefined") { NodePopUp.prototype.setNode = function(n){ // console.log('NodePopUp setNode()'); this.node = n; // positioning NodePopUp regarding node position this.setPositioning(); // update NodePopUp content this.setContent(); }; NodePopUp.prototype.setPositioning = function(){ // switch(true){ // case this.node.x > this.node.wall_limits.right-350-_evolution_zone.right && this.node.y < this.node.wall_limits.top+200: // this.$dom.attr('pos', 'bottom-left'); // break; // case this.node.x > this.node.wall_limits.right-350-_evolution_zone.right: // this.$dom.attr('pos', 'top-left'); // break; // case this.node.y < this.node.wall_limits.top+200: // this.$dom.attr('pos', 'bottom-right'); // break; // default: // this.$dom.attr('pos', 'top-right'); // } switch(true){ case this.node.x > _evolution_zone.right-350 && this.node.y < this.node.wall_limits.top+200: this.$dom.attr('pos', 'bottom-left'); break; case this.node.x > _evolution_zone.right-350: this.$dom.attr('pos', 'top-left'); break; case this.node.y < this.node.wall_limits.top+200: this.$dom.attr('pos', 'bottom-right'); break; default: this.$dom.attr('pos', 'top-right'); } }; NodePopUp.prototype.setContent = function(){ // console.log(this.node); this.$content.html(''); var $entrees = $('
    ').addClass('entrees'); for (var i = 0; i < this.node.entrees.length; i++) { var tid = this.node.entrees[i]; $entrees.append($('').addClass('entree').attr('tid', tid)); } var $chutier_action = $('').addClass('chutier-icon').attr('action', this.node.chutier_action); this.$content .append($entrees) .append('

    '+this.node.title+'

    ') .append('
    '+this.node.description+'
    ') .append($chutier_action); }; NodePopUp.prototype.removeNode = function(){ // console.log('NodePopUp removeNode()'); this.node = false; }; NodePopUp.prototype.draw = function(){ if(this.node){ this.$dom.css({ 'display':"block", 'left':this.node.x+"px", 'top':this.node.y+"px", }); }else{ this.$dom.css({ 'display':"none", }); } }; NodePopUp.initialized = true; } } // ___ _ // | _ \___ _ _ __| |___ _ _ // | / -_) ' \/ _` / -_) '_| // |_|_\___|_||_\__,_\___|_| function render(){ _ctx.clearRect(0, 0, _scene_props.width, _scene_props.height); checkParticulesCollisions(); for (var i = 0; i < _nodes.length; i++) { _nodes[i].onUpdate(); } _node_pop_up.draw(); if(_node_hover_id != -1){ _canvas.style.cursor = 'pointer'; }else{ _canvas.style.cursor = 'auto'; } // check for highlighted entries highlightEntries(); }; // ___ _ _ _ _ // / __| |_ __ _ _ _| |_ /_\ _ _ (_)_ __ ___ // \__ \ _/ _` | '_| _|/ _ \| ' \| | ' \/ -_) // |___/\__\__,_|_| \__/_/ \_\_||_|_|_|_|_\___| function startAnime(){ _physics.onUpdate(render); _physics.play() $('body') .attr('corpus', 'map-ready') .trigger({ 'type':'corpus-map-ready', 'playlist':_playlist }); }; init(); } $(document).ready(function($) { console.log("Corpus ready"); if(drupalSettings.path.isFront && !edlp_mobile.device_is_mobile){ console.log("Corpus new edlpCorpus()"); var edlpcorpus = new EdlpCorpus(); } }); })(jQuery, Drupal, drupalSettings);