diff -r c21cffd36f98 -r 84719280c84d integ/js/vs/_vs.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/integ/js/vs/_vs.js Fri Apr 12 15:08:00 2013 +0200 @@ -0,0 +1,649 @@ +// .................................................................... +// Main Visual Sedimentation Code +// .................................................................... + +// TODO : +// - callback on rollOut + +(function($){ + +// Name Space Plug in Jquery Objects +$.fn.vs = function (){} +$.fn._vs={} + +// All this objects are define in correspondant .js files +$.fn._vs.token = {} +$.fn._vs.draw = {} +$.fn._vs.stream = {} +$.fn._vs.chart = {} +$.fn._vs.phy = {} +$.fn._vs.decay = {} +$.fn._vs.flocculate = {} +$.fn._vs.strata = {} +$.fn._vs.aggregate = {} + + +// Core Classe +var VisualSedimentation = function(element,options){ + + // Attach objects + this.token = $.fn._vs.token + this.draw = $.fn._vs.draw + this.stream = $.fn._vs.stream + this.chart = $.fn._vs.chart + this.phy = $.fn._vs.phy + this.decay = $.fn._vs.decay + this.flocculate = $.fn._vs.flocculate + this.strata = $.fn._vs.strata +// this.aggregate = $.fn._vs.aggregate + this.requestAnimFrame; + + + // Mouse object have to be refactor + this.mouse ={} + this.mouse.x = 0 + this.mouse.y = 0 + this.mouse.isMouseDragging = false + this.mouse.isMouseDown = false + this.mouse.selectedBody = null + + + // Variables + this.dataFlow = []; + this.chartPhySetup= {} + this.tokens = []; + this.world = null; + this.ctx = null; + var elem = $(element); + var self = this; + var tokens = []; + var B2D; + var canvas; + + + // Default Settings + var defaultSettings = { + x:0, + y:0, + width:290.5, + height:300.5, + DOMelement:null, + + chart:{ + x:undefined, + y:undefined, + width:undefined, + height:undefined, + colorRange:d3.scale.category10(), + scale:d3.scale, + type:'StackedAreaChart', + /* + name are based on prefuse tollokit layout : + - CircleLayout, + - StackedAreaChart, + //- bubbleAreaChart, + x AxisLabelLayout, + x AxisLayout, + x CollapsedStackLayout, + x GridLayout, + */ + spacer:5, + //treeLayout:false, + column:3, + wallColor:"rgba(230,230,230,0)", + label:true, + radius:10 // for CircleLayout + }, + data:{ + model:[ + {label:"Column A"}, + {label:"Column B"}, + {label:"Column C"}, + ], + strata:[ + [ + {initValue: 100, label: "Strata 1 col A"} + ],[ + {initValue: 20, label: "Strata 1 col B"} + ],[ + {initValue: 175, label: "Strata 2 col C"} + ] + ], + token:[ + { + timestamp:1, + category:1, + value: 1, + userdata:{}, + callback:{} + } + ], + tokenPast:0, + stream:{ + provider:'generator', + refresh:10000/8, + now:0 + }, + } + , + sedimentation:{ + token:{size:{original:4 + ,minimum:2} + ,visible:true}, // fill color, shape, + incoming:{ + strategy:1, // 1 = one element by one, more = by Groupe + point:[{x:50,y:0}, + {x:100,y:0}, + {x:150,y:0}], + + target:[{x:50,y:0}, + {x:100,y:0}, + {x:150,y:0}] + }, + granulate:{visible:false}, + flocculate:{ + number:1, // 1 = one element by one, more = by groupe of n + action:"buffer", // [buffer,continue] + strategy:"Size", // [BufferSize, Time, AcummulationAreaHeight, Fps, Manual] + bufferSize:5, // number of token to make floculation + bufferTime:1000, // time buffer to make flocullation + bufferHeight:50, // height (pixel) to make floculation + bufferFrameRate:25, // if the computer is to slow floculate + buffer:[] + }, + suspension:{ + height:null, // pourcent,adaptative + incomming:'top', + decay:{power:1.001}, // null + refresh:200 + }, + accumulation:{height:null}, // pourcent ,adaptative + aggregation:{height:0, maxData:0, invertStrata:false}, // pourcent ,adaptative + }, + options:{ + refresh:1000/25, + panel:false, + scale:30, + layout:false, + canvasFirst:true + } + } + + + this.now = function(){ + return(new Date().getTime()) + } + + // get Box2d World + this.globalDecay = function (value){ + if(typeof(value)=='undefined'){ + return this.settings.sedimentation.suspension.decay.power + }else{ + return this.settings.sedimentation.suspension.decay.power=value + } + } + + // get Box2d World + this.getWorld = function (){ + return this.world; + } + + this.chartUpdate = function (cat,y){ + var options = {cat:cat,y:y} + this.chart[this.settings.chart.type](self,'update',options) + } + + // Todo ...... + this.flocculateTokens = function (number){ + return this.flocculate.update(self,number) + } + + // TODO DESTROY ALL TOKENS + this.flocculateAll = function(){ + return this.flocculate.all(self) + } + + // Add token function + this.addToken = function (element){ + //var token = this.token.addToken(self,element) + return this.token.addToken(self,element); + } + + // Select token fonction + this.selectAll = function (key,value){ + return this.token.selectAll(self,key,value); + } + + // Select token fonction + this.select = function (key,value){ + return this.token.select(self,key,value); + } + + // update a categoryr in the chart + this.updateAll = function (values){ + var tokens = this.chart.updateAll(self,key,value) + return tokens; + } + + // update a category in the chart + this.update = function (key,value){ + var tokens = this.chart.update(self,key,value) + return tokens; + } + + + /// Settings without + + + //////////////////////////////////////////////////////// TO CLEAN + // SAM @ROM1 : are you sure you need that ? extend doing it well normally + // Merge options with defaults + // http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically + + //console.log("////////") + //options.model = modelToStrata(options.data.model) + + function merge_options(obj1,obj2){ + var obj3 = {}; + for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; } + for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; } + return obj3; + } + + merge_options(defaultSettings, options); + if(options.data!=undefined) + defaultSettings.data = options.data; + + //////////////////////////////////////////////////////////////////////////////////// + // Merge option and add the DOMelement to setting + //this.settings = $.extend(defaultSettings, options || {}); + this.settings = $.extend(true,defaultSettings, options); + this.settings.DOMelement = element + //console.log('settings after extend',this.settings) + + // ----------------------------------------------- + // SIMPLE DEFAULT SETTING FOR RETRO COMPATIBILITY + // + if(typeof(this.settings.chart.width) =="undefined"){this.settings.chart.width = this.settings.width} + if(typeof(this.settings.chart.x) =="undefined")this.settings.chart.x=0 + if(typeof(this.settings.chart.y) =="undefined")this.settings.chart.y=0 + if(typeof(this.settings.chart.height)=="undefined")this.settings.chart.height=this.settings.height + if(typeof(this.settings.stream) =="undefined"){this.settings.stream={}} + if(typeof(this.settings.stream.now) =="undefined"){this.settings.stream.now=0} + if(typeof(this.settings.stream.provider)=="undefined"){this.settings.stream.provider='generator'} + if(typeof(this.settings.stream.refresh)=="undefined"){this.settings.stream.refresh=1000} + if(typeof(this.settings.data.tokenPast)=="undefined"){this.settings.data.tokenPast=0} + if(typeof(this.settings.data.tokens)=="undefined"){this.settings.data.tokens=[]} + + // FOR ROM1 setting by default aggregation : + if(typeof(this.settings.data.strata) !="undefined" && this.settings.data.strata.length!=0){ + if(typeof(this.settings.sedimentation.aggregation) =="undefined"){ + this.settings.sedimentation.aggregation = {} + } + if(typeof(this.settings.sedimentation.aggregation.height) =="undefined"){ + this.settings.sedimentation.aggregation.height = this.settings.chart.height/2 + } + if(typeof(this.settings.sedimentation.aggregation.maxData) =="undefined"){ + this.settings.sedimentation.aggregation.maxData = 10 + } + } + // END + + + // Initialisation - Private method + this.init = function(){ + // requestAnim shim layer by Paul Irish + // not use yet, to add + this.requestAnimFrame = (function(){ + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(/* function */ callback, /* DOMElement */ element){ + window.setTimeout(callback, 1000 / 60); + }; + })(); + + //console.log(this.settings) + //console.log('Initialisation'); + + // Create the physical simulation + this.world = new this.phy.b2World( + new this.phy.b2Vec2(0, 0) //gravity + , true //allow sleep + ); + + // Create container and canvas for physical simulation drawing + var container = element.appendChild(document.createElement("div")); + container.id = "box_sediviz_"+GUID() + container.width = this.settings.width; // TOFIX + container.height = this.settings.height; + + //console.log(container.id) + // Allocate the new Element + this.settings.DOMelement = container + + canvas = container.appendChild(document.createElement("canvas")); + canvas.id = "canvas"; + canvas.width = this.settings.width; // TOFIX + canvas.height = this.settings.height; + canvas.style.position = "absolute" + + //console.log(this.settings.width,this.settings.height) + this.ctx = canvas.getContext("2d"); + + // Construct the Chart + this.chart[this.settings.chart.type](self,'init') + + + // Draw d3 + //if(typeof(this.settings.options.debugaggregate)=="undefined"){ + // this.aggregate.init(self); + //} + // Initiatlise stream + this.stream.init(self) + // Initiatlise decay + this.flocculate.init(self) + // Update stream + this.stream.update(self); + + // Initiatlise tokens + this.token.init(self) + + //FORCE UPDATE CHART due to (bug positionnement ) @rom1 + this.strata.init(this) + + // Update the physical simulation + window.setInterval( + function(){self.update(self);}, + self.settings.options.refresh/2 + ); + // Refresh canvas drawings + window.setInterval( + function(){self.draw.update(self);}, + self.settings.options.refresh + ); + // Update Decay + window.setInterval( + function(){self.decay.update(self);}, + self.settings.sedimentation.suspension.refresh + ); + //this.decay.update(self); + + self.strata.update(self) + + + // MOUSE PART + // inspired by box2d stuffs, have to clean and finish this ! + // http://www.emanueleferonato.com/2008/11/20/dragging-objects-with-box2d-flash/ + // -------------------------- + this.getBodyAtMouse=function (_this) { + + var x = _this.mouse.x/_this.settings.options.scale + var y =_this.mouse.y/_this.settings.options.scale + var mousePVec = new _this.phy.b2Vec2(x,y); + var aabb = new _this.phy.b2AABB(); + var area = 0.001 + + //console.log(_this.mouse.x,_this.mouse.y) + aabb.lowerBound.Set(x - area, y - area); + aabb.upperBound.Set(x + area, y + area); + + // Query the world for overlapping shapes. + _this.mouse.selectedToken = null; + + // MERCI JULIEN POUR LE CLOSURE + //selectedBody + _this.world.QueryAABB(function(fixture){ + return getBodyCB(fixture,_this,mousePVec) + }, aabb); + + return _this.mouse.selectedToken; + } + //http://stackoverflow.com/questions/11674200/how-to-send-prototype-method-as-a-callback-in-javascript + // pb here + function getBodyCB(fixture,_this,mousePVec) { + //console.log("phy",phy) + //console.log("fixture",fixture.m_userData.type,fixture) + //_this.mouse.elementpoi = fixture.GetBody() + _this.mouse.selectedToken = fixture; + + if(fixture.GetBody().GetType() != _this.phy.b2Body.b2_staticBody) { + if(fixture.GetShape().TestPoint(fixture.GetBody().GetTransform(), mousePVec)) { + _this.mouse.selectedToken = fixture; + return false; + } + } + return true; + } + + this.handleMouseMove = function(e,_this) { + canvasPosition = DOMabsOffset(_this.settings.DOMelement) + _this.mouse.x = (e.clientX - (canvasPosition.offsetLeft- this.getScrollPosition()[0])); + _this.mouse.y = (e.clientY - (canvasPosition.offsetTop- this.getScrollPosition()[1])); + //if( _this.mouse.isMouseDown){ console.log(_this.mouse.y,canvasPosition.y)} + //console.log("mouse",e.clientX,e.clientY ) + //console.log("mouse",canvasPosition.x,canvasPosition.y ) + //console.log("=",_this.mouse.x,_this.mouse.y) + }; + // from + this.getScrollPosition= function(){ + return Array((document.documentElement && document.documentElement.scrollLeft) || window.pageXOffset || self.pageXOffset || document.body.scrollLeft,(document.documentElement && document.documentElement.scrollTop) || window.pageYOffset || self.pageYOffset || document.body.scrollTop); + } + + document.addEventListener("mousemove", function (e){onDocumentMouseMove(e,self)}); + document.addEventListener("mouseup", function (e){onDocumentMouseUp(e,self)}); + document.addEventListener("mousedown", function (e){onDocumentMouseDown(e,self)}); + + + + function onDocumentMouseOver(e,_this) { + + var s = _this.getBodyAtMouse(_this); + if(s!=null){ + if(typeof(s.m_userData)!="undefined"){ + if(typeof(s.m_userData.callback)!="undefined"){ + if(typeof(s.m_userData.callback.mouseover)=="function"){ + var t = _this.select('ID',s.m_userData.ID) + s.m_userData.callback.mouseover(t) + } + + if(typeof(s.m_userData.callback.mouseout)=="function"){ + //console.log("mouseout exist") + var t = _this.select('ID',s.m_userData.ID) + var mouseoutTrigger + var rollOut = function(){ + var mt = mouseoutTrigger + var tt = t + var ici = _this + var ss = s + return function(){ + var s = ici.getBodyAtMouse(ici); + var mo = false; + if(s!=null){ + if(typeof(s.m_userData)!="undefined"){ + if(s.m_userData.ID==tt.attr('ID')){ + mo=false + }else{ + mo=true + } + }else{ + mo=true + } + }else{ + mo=true; + } + if(mo){ + ss.m_userData.callback.mouseout(tt) + clearInterval(mouseoutTrigger) + } + } + }; + mouseoutTrigger = window.setInterval(rollOut(),100) + } + } + } + } + } + + function onDocumentMouseDown(e,_this) { + //console.log("onDocumentMouseDown") + _this.mouse.isMouseDown = true; + // return false; + _this.handleMouseMove(e,_this); + var s = _this.getBodyAtMouse(_this); + if(s!=null){ + if(typeof(s.m_userData)!="undefined"){ + if(typeof(s.m_userData.callback)!="undefined"){ + if(typeof(s.m_userData.callback.onclick)=="function"){ + var t = _this.select('ID',s.m_userData.ID) + s.m_userData.callback.onclick(t) + } + } + } + } + } + + function onDocumentMouseUp(e,_this) { + _this.mouse.isMouseDown = false; + // isMouseDown = false; + // return false; + //console.log("onDocumentMouseUp") + } + function onDocumentMouseMove( e,_this ) { + + if(_this.mouse.isMouseDown){ + _this.mouse.isMouseDragging = true; + _this.mouse.x = e.clientX; + _this.mouse.y = e.clientY; + + }else{ + _this.handleMouseMove(e,_this); + onDocumentMouseOver("move",_this) + } + //console.log("m",_this) + } + } + + + this.mouse.update = function (s) { + if(isMouseDown && (!mouseJoint)) { + var body = getBodyAtMouse(); + if(body) { + var md = new b2MouseJointDef(); + md.bodyA = world.GetGroundBody(); + md.bodyB = body; + md.target.Set(mouseX, mouseY); + md.collideConnected = true; + md.maxForce = 300.0 * body.GetMass(); + mouseJoint = world.CreateJoint(md); + body.SetAwake(true); + } + } + + if(mouseJoint) { + if(isMouseDown) { + mouseJoint.SetTarget(new b2Vec2(mouseX, mouseY)); + } else { + world.DestroyJoint(mouseJoint); + mouseJoint = null; + } + } + + }; + + + + // MOUSE END + // -------------------------- + + this.update = function (s) { + this.world.Step(1 / 60, 10, 10); + this.world.DrawDebugData(); + this.world.ClearForces(); + //console.log('u') + } + + var drawInit = function(){ + ctx.fillStyle = "rgb(200,0,0)"; + this.ctx.font = "14pt Calibri,Geneva,Arial"; + this.ctx.fillText("Canvas ready for Visual Sedimentation ", 10, 20); + window.setInterval( + $.fn.vs.draw.refresh(ctx,world,this.settings) + , this.settings.options.refresh); + console.log("draw Init ") + } + + + var DOMabsOffset = function(target){ + var top = target.offsetTop; + var left = target.offsetLeft; + + while(target = target.offsetParent) { + top += target.offsetTop; + left += target.offsetLeft; + } + + return {offsetLeft:left, offsetTop:top}; + }; + + // GUID generator from : + // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript + var GUID = function(){ + var S4 = function () + { + return Math.floor( + Math.random() * 0x10000 /* 65536 */ + ).toString(16); + }; + + return ( + S4() + S4() + "-" + + S4() + "-" + + S4() + "-" + + S4() + "-" + + S4() + S4() + S4() + ); + } + + // clone object + // http://stackoverflow.com/questions/728360/copying-an-object-in-javascript + function clone(obj) { + if (null == obj || "object" != typeof obj) return obj; + var copy = obj.constructor(); + for (var attr in obj) { + if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; + } + return copy; + } + this.utile = {} + this.utile.GUID = GUID + this.utile.clone = clone + + this.settings = $.extend(this.settings, {} || {}); + //console.log("ici",this.settings) + this.init(); + + }; + +$.fn.vs = function(options){ + if (!arguments.length){var options={}} + //console.log('$.fn.vs settings',options) + return this.each(function(){ + var element = $(this); + // Return early if this element already has a plugin instance + if (element.data('VisualSedimentation')) return; + var visualSedimentation = new VisualSedimentation(this,options); + // Store plugin object in this element's data + element.data('visualSedimentation', visualSedimentation); + //visualSedimentation.test(); + }); + }; + +})(jQuery); + + + + +