"use strict"; FW_version["zwave_neighborlist.js"] = "$Id$"; var zw_visible; var svgns = 'xmlns="http://www.w3.org/2000/svg"'; function zw_nl(fhemFn) { log("ZWNL called with "+fhemFn); zw_visible = !zw_visible; var txt = (zw_visible ? 'Hide' : 'Show'); var width=$("#content").width()-20, height=$("#content").height()-20; $('#ZWDongleNr a#zw_snm').html(txt+' neighbor map'); if(!zw_visible) { $('#ZWDongleNr span').remove(); $("#ZWDongleNrSVG") .css({width:0, height:0}) .html(''); return; } $('#ZWDongleNr').append(''+ '  Start auto layout'+ '  Send layout to FHEM'); FW_cmd(FW_root+"?cmd={"+fhemFn+"}&XHR=1", function(r){ var xpos=20, ypos=20, fnRet = JSON.parse(r); $("#zw_save").toggle(fnRet.saveFn ? true : false); var cnt=0; for(var elName in fnRet.el) { var el = fnRet.el[elName]; el.lines = []; el.name = elName; el.elHash = fnRet.el; if(el.img) { el.width = 64; el.height = 64+20; } else { el.width = el.height = 30; } if(!el.pos.length) { el.pos = [xpos, ypos]; xpos += 150; if(xpos+150 >= width) xpos = 20, ypos += 50; } el.x = el.pos[0]; el.y = el.pos[1]; cnt++; } zw_draw(fnRet, width, height); $('#ZWDongleNr a#zw_al').click(function(){ zw_al(fnRet, width, height); }); $('#ZWDongleNr a#zw_save').click(function(){ for(var eName in fnRet.el) { var el = fnRet.el[eName]; if(el.pos[0] != el.x || el.pos[1] != el.y) { log("SavePos:"+eName); el.x = Math.round(el.x*100)/100; el.y = Math.round(el.y*100)/100; el.pos[0] = el.x; el.pos[1] = el.y; var cmd = sprintf(fnRet.saveFn, eName, el.x+","+el.y); FW_cmd(FW_root+"?cmd="+cmd+"&XHR=1"); } } }); }); } function zw_draw(fnRet, width, height) { var h = fnRet.el; var svg = ''; svg += ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''; svg += ''; var ld={}; for(var o in h) { if(h[o].txt && h[o].neighbors) for(var i1=0; i1'; if(o.title) s += ''+o.title+''; s += ''; if(o.img) s += ''; s += ''+o.txt+'' s +=''; return s; } function zw_calcPos(o, n) { return { x: o.x+o.width/2, y: o.y+o.height/2 }; } function zw_drawline(fnRet, ld, h, o, i1) { var n = h[o].neighbors[i1]; var ns = (h[o].neighborstyles ? h[o].neighborstyles[i1] : "") if(!h[o] || !h[n]) return ""; var bidi = false; if(!fnRet.skipArrow) { for(var i1=0; i1'; } function zw_adjustLines(h, name) { var la = h[name].lines; for(var i1=0; i1 1) { return; } event.preventDefault(); var touch = event.originalEvent.changedTouches[0], simulatedEvent = document.createEvent('MouseEvents'); // Initialize the simulated mouse event using the touch event's coordinates simulatedEvent.initMouseEvent( simulatedType, // type true, // bubbles true, // cancelable window, // view 1, // detail touch.screenX, // screenX touch.screenY, // screenY touch.clientX, // clientX touch.clientY, // clientY false, // ctrlKey false, // altKey false, // shiftKey false, // metaKey 0, // button null // relatedTarget ); // Dispatch the simulated event to the target element event.target.dispatchEvent(simulatedEvent); } /** * Handle the jQuery UI widget's touchstart events * @param {Object} event The widget element's touchstart event */ mouseProto._touchStart = function (event) { var self = this; // Ignore the event if another widget is already being handled if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) { return; } // Set the flag to prevent other widgets from inheriting the touch event touchHandled = true; // Track movement to determine if interaction was a click self._touchMoved = false; // Simulate the mouseover event simulateMouseEvent(event, 'mouseover'); // Simulate the mousemove event simulateMouseEvent(event, 'mousemove'); // Simulate the mousedown event simulateMouseEvent(event, 'mousedown'); }; /** * Handle the jQuery UI widget's touchmove events * @param {Object} event The document's touchmove event */ mouseProto._touchMove = function (event) { // Ignore event if not handled if (!touchHandled) { return; } // Interaction was not a click this._touchMoved = true; // Simulate the mousemove event simulateMouseEvent(event, 'mousemove'); }; /** * Handle the jQuery UI widget's touchend events * @param {Object} event The document's touchend event */ mouseProto._touchEnd = function (event) { // Ignore event if not handled if (!touchHandled) { return; } // Simulate the mouseup event simulateMouseEvent(event, 'mouseup'); // Simulate the mouseout event simulateMouseEvent(event, 'mouseout'); // If the touch interaction did not move, it should trigger a click if (!this._touchMoved) { // Simulate the click event simulateMouseEvent(event, 'click'); } // Unset the flag to allow other widgets to inherit the touch event touchHandled = false; }; /** * A duck punch of the $.ui.mouse _mouseInit method to support touch events. * This method extends the widget with bound touch event handlers that * translate touch events to mouse events and pass them to the widget's * original mouse event handling methods. */ mouseProto._mouseInit = function () { var self = this; // Delegate the touch handlers to the widget's element self.element.bind({ touchstart: $.proxy(self, '_touchStart'), touchmove: $.proxy(self, '_touchMove'), touchend: $.proxy(self, '_touchEnd') }); // Call the original $.ui.mouse init method _mouseInit.call(self); }; /** * Remove the touch event handlers */ mouseProto._mouseDestroy = function () { var self = this; // Delegate the touch handlers to the widget's element self.element.unbind({ touchstart: $.proxy(self, '_touchStart'), touchmove: $.proxy(self, '_touchMove'), touchend: $.proxy(self, '_touchEnd') }); // Call the original $.ui.mouse destroy method _mouseDestroy.call(self); }; })(jQuery); function GM() { this.aid=null; this.scaleFactor =1.4; // scaling in respect to calculated window space this.scaleByCenterDist=-1; // scaling in respect to mean target center distance (mean aid[i][0]) this.frameDelayInitial=250; // initial value of increasing delay at each timestep this.slowdownCycle =30; // number of timesteps after that delay is increased this.inertia =0.7; // part of velocity kept in one timestep this.damperInitial =4; // initial value of increasing damper that cool down motion with time this.damperFactor =1.052; // factor the damper is increased by in one timestep this.damperMax =60; // max. value of damper this.springForce0 =2.500; // force between each item and the central item s0 trying to keep them at aid[][]-distance this.springForce =0.015; // force between each item pair except the central item s0 this.centeringForce =0.1; // force that pulls the center of gravity towards the central item // overlap avoiding this.repelInitial = 0.1 this.repelDelay = 0; // nr. of timesteps without repulsion this.repelIncrease =0.02; // amount the repelling force that keeps items non overlapping increases each timestep this.repelMax =0.9; // max amount of repelling force. this.paddingFactor =2.00; // factor by which an item is enlarged while avoiding overlap var nrItems, items; var maxX, maxY, minX, minY; // bounds of drawing area var scaleX,scaleY; var cogX, cogY; var cycle=0; var damper; var repel = this.repelInitial; this.getMeanItemSize=function() { var meanW=0, meanH=0; for(var i=1; imaxX) items[i].x=maxX-w; if (items[i].x-wmaxY) items[i].y=maxY-h; if (items[i].y-h=0 && values[i]0 && !no_overlap) { var oMin=positiveMin(Array(oLeft, oRight, oTop, oBottom)); var distance=Math.sqrt(dx*dx+dy*dy); var repelScaler=repel*oMin/distance; if(item1.idx != 0) { item1.x+=dx*repelScaler; item1.y+=dy*repelScaler; } item2.x-=dx*repelScaler; item2.y-=dy*repelScaler; } } this.layoutStep = function () { log("LS:"+cycle); var thisMap=this; this.layoutItems(); this.recenterItems(); this.updateItems(); if (damperthis.repelDelay && repelthis.slowdownCycle) this.gm_frameDelay++; if(cycle++ == 100) { this.finishFn(); return; } this.gm_timeout = setTimeout(function(){thisMap.layoutStep()}, this.gm_frameDelay); } this.meanTargetCenterDistance = function() { var r=0; for(var i1=1; i1needle) high=mid-1; else if (value0) values.push(this.aid[i][j]); values.sort(); for (var i=0; i0) this.aid[i][j]= 1-(search(this.aid[i][j], values)/values.length); } this.init=function () { nrItems=this.aid[0].length; maxX=this.maxX; maxY=this.maxY; minX=this.minX; minY=this.minY; this.equalizeAid(); this.resetItemPositions(); this.gm_timeout = setTimeout(function(){gm.layoutStep()},10); } }