123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574 |
- /**
- * @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
- */
- /**
- * depends on :
- *
- * physics.js : http://jonobr1.com/Physics/#
- * EaselJS : https://createjs.com/docs/easeljs/modules/EaselJS.html
- *
- */
- (function($) {
- EdlpCorpus = function(){
- var _activated = true;
- var _$container = $('body');
- var _$canvas = $('<canvas id="corpus-map">').appendTo(_$container);
- var _canvas = _$canvas[0];
- var _ctx = _canvas.getContext('2d');
- var _canvas_props = {
- 'margin_top':100,
- 'margin_right':0,
- 'margin_bottom':100,
- 'margin_left':0
- };
- var _physics = new Physics();
- // var _stage = new createjs.Stage('corpus-map');
- var _nodes = [];
- // var _particules = [];
- // var _base_radius = 3; // nodes radius (real radius, not diametre)
- var _p_velocity_factor = 0.5;
- 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 _node_pop_up;
- // Colors depend on edlp_vars loaded by edlptheme
- // console.log('Corpus : edlp_vars', edlp_vars);
- // ____ _ __
- // / _/___ (_) /______
- // / // __ \/ / __/ ___/
- // _/ // / / / / /_(__ )
- // /___/_/ /_/_/\__/____/
- function init(){
- console.log("EdlpCorpus init()");
- // console.log("document", document);
- initMap();
- };
- function initMap(){
- console.log("EdlpCorpus initMap()");
- // console.log('_physics',_physics);
- initCanvas();
- if(_activated){
- loadCorpus();
- }else{
- _$canvas.addClass('de-activated');
- }
- };
- // ______
- // / ____/___ _____ _ ______ ______
- // / / / __ `/ __ \ | / / __ `/ ___/
- // / /___/ /_/ / / / / |/ / /_/ (__ )
- // \____/\__,_/_/ /_/|___/\__,_/____/
- function initCanvas(){
- // resize the canvas to fill browser window dynamically
- window.addEventListener('resize', onResizeCanvas, false);
- onResizeCanvas();
- };
- function onResizeCanvas() {
- _canvas.width = window.innerWidth;
- _canvas.height = window.innerHeight;
- for (var i = 0; i < _nodes.length; i++) {
- _nodes[i].onResizeCanvas();
- }
- };
- // ___ _
- // / | (_)___ __ __
- // / /| | / / __ `/ |/_/
- // / ___ | / / /_/ /> <
- // /_/ |_|_/ /\__,_/_/|_|
- // /___/
- function loadCorpus(){
- // console.log('drupalSettings',drupalSettings);
- // console.log('window.location', window.location);
- var path = window.location.origin + drupalSettings.basepath + "edlp/corpus";
- $.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);
- initNodePopup();
- buildNodes(data.nodes);
- initEvents();
- startAnime();
- };
- // _ __ __
- // / | / /___ ____/ /__ _____
- // / |/ / __ \/ __ / _ \/ ___/
- // / /| / /_/ / /_/ / __(__ )
- // /_/ |_/\____/\__,_/\___/____/
- function buildNodes(nodes){
- console.log("buildNodes", nodes);
- var x,y,d;
- for (var i in nodes) {
- d = i < 1 ? true : false;
- _nodes.push(new Node(i,nodes[i],d));
- }
- };
- function Node(i,node,d){
- this.id = i;
- for(key in node)
- this[key] = node[key];
- this.debug = d;
- this.mass = 8;
- this.velocity_threshold = 0.01;
- // define radius regarding entries length
- switch(true){
- case this.entrees.length > 1 & this.entrees.length <= 3:
- this.r = 7.5;
- break;
- case this.entrees.length > 3:
- this.r = 10;
- break;
- default:
- this.r = 5;
- break;
- }
- this.e_color = 'e_col_'+this.entrees[Math.floor(Math.random(this.entrees.length))];
- this.hover = false;
- this.opened = 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);
- // physics
- 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);
- // if(this.id == '620'){
- // _node_pop_up.setNode(this);
- // }
- };
- Node.prototype.calcWallLimits = function(){
- this.wall_limits = {
- top: _canvas_props.margin_top +this.r,
- right: _canvas.width -_canvas_props.margin_right -this.r,
- bottom: _canvas.height -_canvas_props.margin_bottom -this.r,
- left: _canvas_props.margin_left +this.r
- }
- };
- Node.prototype.onResizeCanvas = function(){
- this.calcWallLimits();
- // TODO: when canvas is smaller what about nodes hors champs, they are coming back alone but it's too long
- };
- Node.prototype.onUpdate = function(){
- // if(this.id == 0){
- // console.log(_physics.playing);
- // }
- if(!this.p.resting()){
- this.checkVelocityThreshold();
- this.checkWallBouncing();
- this.updatePos();
- }
- this.checkMouse();
- // if(this.debug)
- // console.log("Node pos: ", {x:this.x, y:this.y});
- this.draw();
- };
- Node.prototype.checkVelocityThreshold = function(){
- 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(){
- if(
- (this.x < this.wall_limits.left && this.p.velocity.x < 0)
- || (this.x > this.wall_limits.right && this.p.velocity.x > 0)
- ){
- // console.log("bounce x");
- this.p.velocity.multiplyScalarXY(-1, 1).multiplyScalar(0.75);
- }
- if(
- (this.y < this.wall_limits.top && this.p.velocity.y < 0)
- || (this.y > this.wall_limits.bottom && this.p.velocity.y > 0)
- ){
- // console.log("bounce y");
- this.p.velocity.multiplyScalarXY(1,-1).multiplyScalar(0.75);
- }
- };
- 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.hover = true;
- _node_hover_id = this.id;
- _node_pop_up.setNode(this);
- }
- }else{
- 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.prototype.close = function(){
- this.opened = false;
- };
- Node.prototype.draw = function(){
- // carre plein
- // clouleur aléatoire ds les entrees
- // 3 tailles :
- // - 1 entree : petit carre 5px
- // - 2-3 entrees : moyen 7.5px
- // - >3 entrees : grand 10px
- // actif entouré de rouge
- _ctx.beginPath();
- _ctx.fillStyle = !this.p.resting() ? edlp_vars[this.e_color] : 'rgb(0, 0, 0)';
- // _ctx.fillStyle = edlp_vars[this.e_color];
- _ctx.fillRect(this.x - this.r,this.y - this.r,this.r*2,this.r*2);
- if(this.opened){
- _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);
- }
- _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(){
- // pre create vars to save memory;
- var d, full_rad,
- newVelX1, newVelY1, newVelX2, newVelY2,
- makeup, angle;
- // colisions between _particules
- for (var n = 0; n < _nodes.length; n++) {
- for (var q = n+1; q < _nodes.length; q++) {
- if(q===n) continue;
- // if(!_nodes[q].moving) continue;
- d = _nodes[n].p.distanceTo(_nodes[q].p);
- full_rad = _nodes[n].r + _nodes[q].r;
- // if not colliding skip following
- if(d > full_rad) continue;
- // apply new forces if colliding
- newVelX1 = (_nodes[n].p.velocity.x * (_nodes[n].p.mass - _nodes[q].p.mass)
- + (2 * _nodes[q].p.mass * _nodes[q].p.velocity.x)) / (_nodes[n].p.mass + _nodes[q].p.mass);
- newVelY1 = (_nodes[n].p.velocity.y * (_nodes[n].p.mass - _nodes[q].p.mass)
- + (2 * _nodes[q].p.mass * _nodes[q].p.velocity.y)) / (_nodes[n].p.mass + _nodes[q].p.mass);
- newVelX2 = (_nodes[q].p.velocity.x * (_nodes[q].p.mass - _nodes[n].p.mass)
- + (2 * _nodes[n].p.mass * _nodes[n].p.velocity.x)) / (_nodes[n].p.mass + _nodes[q].p.mass);
- newVelY2 = (_nodes[q].p.velocity.y * (_nodes[q].p.mass - _nodes[n].p.mass)
- + (2 * _nodes[n].p.mass * _nodes[n].p.velocity.y)) / (_nodes[n].p.mass + _nodes[q].p.mass);
- _nodes[n].p.velocity.x = newVelX1;
- _nodes[n].p.velocity.y = newVelY1;
- _nodes[q].p.velocity.x = newVelX2;
- _nodes[q].p.velocity.y = newVelY2;
- _nodes[n].p.velocity.multiplyScalar(0.85);
- _nodes[q].p.velocity.multiplyScalar(0.85);
- // move particles if they overlap
- if (d < full_rad) {
- makeup = full_rad/2 - d/2;
- angle = Math.atan2(_nodes[q].p.position.y - _nodes[n].p.position.y, _nodes[q].p.position.x - _nodes[n].p.position.x);
- _nodes[q].p.position.x += makeup * Math.cos(angle);
- _nodes[q].p.position.y += makeup * Math.sin(angle);
- angle += Math.PI;
- _nodes[n].p.position.x += makeup * Math.cos(angle);
- _nodes[n].p.position.y += makeup * Math.sin(angle);
- }
- }
- }
- };
- // show opened audio node
- function openNode(id){
- closeNode();
- _node_opened_id = id;
- _nodes[id].open();
- }
- function closeNode(){
- if(_node_opened_id != -1){
- _nodes[_node_opened_id].close();
- _node_opened_id = -1;
- }
- }
- // ______ __
- // / ____/ _____ ____ / /______
- // / __/ | | / / _ \/ __ \/ __/ ___/
- // / /___ | |/ / __/ / / / /_(__ )
- // /_____/ |___/\___/_/ /_/\__/____/
- function initEvents(){
- _$canvas
- .on('mousemove', function(event) {
- event.preventDefault();
- // console.log("onMouseMove");
- _m_pos.x = event.originalEvent.clientX;
- _m_pos.y = event.originalEvent.clientY;
- // console.log("/ _ / - / _ /");
- // console.log("Node pos: ", {x:_nodes[0].x, y:_nodes[0].y});
- // console.log("Mouse pos: ", {x:_m_pos.x, y:_m_pos.y});
- })
- .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':{
- 'id':_node_hover_id,
- 'nid':_nodes[_node_hover_id].nid,
- 'audio_url':_nodes[_node_hover_id].son_url
- },
- };
- _$canvas.trigger(event);
- openNode(_node_hover_id);
- }else{
- // console.log('corpus : click on map');
- _$canvas.trigger('corpus-cliked-on-map');
- }
- }
- })
- .on('audio-node-closed', function(e){
- closeNode();
- });
- _$entrees_block_termlinks.on('click', function(event) {
- event.preventDefault();
- var $li = $(this).parents('li');
- if(!$li.is('.opened')){
- _$entrees_block_termlinks.parents('li').removeClass('opened');
- $li.addClass('opened');
- }else{
- $li.removeClass('opened');
- }
- 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));
- }
- this.$content
- .append($entrees)
- .append('<h2 class="title">'+this.node.title+'</h2>')
- .append('<section class="description">'+this.node.description+'</section>');
- // TODO: favoris marker
- };
- 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, _canvas.width, _canvas.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';
- highlightEntries();
- // _node_pop_up.visible = true;
- }else{
- _canvas.style.cursor = 'auto';
- _$entrees_block_termlinks.removeClass('highlighted');
- // _node_pop_up.visible = false;
- }
- };
- // _ _ _ _ _ _ _ _ ___ _ _
- // | || (_)__ _| |_ | |_(_)__ _| |_| |_| __|_ _| |_ _ _(_)___ ___
- // | __ | / _` | ' \| / / / _` | ' \ _| _|| ' \ _| '_| / -_|_-<
- // |_||_|_\__, |_||_|_\_\_\__, |_||_\__|___|_||_\__|_| |_\___/__/
- // |___/ |___/
- function highlightEntries(){
- _$entrees_block_termlinks.removeClass('highlighted');
- var entree;
- for (var i = 0; i < _nodes[_node_hover_id].entrees.length; i++) {
- entree = _nodes[_node_hover_id].entrees[i];
- _$entrees_block_termlinks.filter(function(){
- return $(this).attr('tid') == entree;
- }).addClass('highlighted');
- }
- }
- // ___ _ _ _ _
- // / __| |_ __ _ _ _| |_ /_\ _ _ (_)_ __ ___
- // \__ \ _/ _` | '_| _|/ _ \| ' \| | ' \/ -_)
- // |___/\__\__,_|_| \__/_/ \_\_||_|_|_|_|_\___|
- function startAnime(){
- _physics.onUpdate(render);
- _physics.play()
- $('body').trigger('corpus-map-ready');
- };
- init();
- }
- $(document).ready(function($) {
- var edlpcorpus = new EdlpCorpus();
- });
- })(jQuery);
|