1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291 |
- /**
- * @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,
- '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;
- _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"
- var href = window.location.origin + drupalSettings.path.baseUrl +_settings.articlesindex_url;
- _$articles_link = $('<a>')
- .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(
- $('<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;
- // // 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 = $('<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);
|