12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235 |
- /**
- * @Author: Bachir Soussi Chiadmi <bach>
- * @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 = $('<canvas id="corpus-map">').appendTo(_$container);
- var _canvas = _$canvas[0];
- var _ctx = _canvas.getContext('2d');
- var _dpi = window.devicePixelRatio;
- var _scene_props = {
- width:window.innerWidth,
- height:window.innerHeight,
- // 'margin_top':90, // with red border on head
- 'margin_top':75, // without red border on head
- // 'margin_top':0,
- 'margin_right':0,
- 'margin_bottom':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(){
- 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
- });
- }
- };
- 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 || na.center) continue;
- 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;
- _evolution_zone.left = Math.max(_scene_props.width/5, left+20);
- _evolution_zone.right = 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;
- // 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('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"
- _$articles_link = $('<a>')
- .html('Articles')
- .attr("href", "#articles")
- .addClass('articles-link')
- .on('click', onCLickedOnArticles);
- $('.item-list ul',_$entrees_block).append(
- $('<li>').append(
- $('<span class="oblique-wrapper">').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;
- for (var i = 0; i < _no_articles_nodes.length; i++) {
- _no_articles_nodes[i].fade();
- }
- updateRandomPlaylist(_articles_nodes);
- if(typeof _paq !== 'undefined'){
- // trackEvent(category, action, [name], [value])
- _paq.push(['trackEvent', 'Corpus Articles', 'on']);
- }
- };
- function deactivateArticlesFilter(){
- //console.log('deactivateArticlesFilter');
- _articles_filter_on = false;
- for (var i = 0; i < _no_articles_nodes.length; i++) {
- _no_articles_nodes[i].unFade();
- }
- 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();
- });
- _$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 = $('<div>')
- .addClass('node-popup')
- .attr('pos', 'top-right')
- .appendTo('body');
- this.$content = $('<div>').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 && 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:
- 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 = $('<div>').addClass('entrees');
- for (var i = 0; i < this.node.entrees.length; i++) {
- var tid = this.node.entrees[i];
- $entrees.append($('<span>').addClass('entree').attr('tid', tid));
- }
- var $chutier_action = $('<span>').addClass('chutier-icon').attr('action', this.node.chutier_action);
- this.$content
- .append($entrees)
- .append('<h2 class="title">'+this.node.title+'</h2>')
- .append('<section class="description">'+this.node.description+'</section>')
- .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($) {
- if(drupalSettings.path.isFront && !edlp_mobile.device_is_mobile){
- var edlpcorpus = new EdlpCorpus();
- }
- });
- })(jQuery, Drupal, drupalSettings);
|