--- /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);
+
+
+
+
+