related.js_2 (Entry Nr. 494, by user 39 | edit) |
|
| /******************************************************************************
* animated item relationship distance map
*
* Part of Gnod, the Global Network of Dreams. (c) Marek Gibney
*
* Animates html elements with id's "s0", "s1",...
*
* Tries to keep the distances between them as given by an array gnodMap.aid[][],
* where aid[4][7] is the proposed distance "s4" should have to "s7".
*
* The element with id "s0" allways stays in the center.
*
* settings can be made by altering several values in gnodMap, e.g.
* gnodMap.scale=0.4; // makes the map smaller
*
* DEPRECATED (see also end of this file):
* settings can be set via a global object "gnodMapSettings":
* * minX, maxX, minY, maxY: boundaries of drawing area
* * offsetX, offsetY: move center out of the drawing area's center.
* * nrItems: maximum number items to be displayed, even if Aid[][] is larger
*
*
*****************************************************************************/
/**
* A moving HTML element
*/
function mg_2d_element(id)
{
this.id=id;
this.x=0;
this.y=0;
this.speedX=0;
this.speedY=0;
this.element=document.getElementById("s"+this.id);
this.name=this.element.innerHTML;
this.width =this.element.offsetWidth;
this.height=this.element.offsetHeight;
this.inertia=0.7;
this.update=function(damper)
{
this.element.style.left=this.x-this.width /2;
this.element.style.top =this.y-this.height/2;
this.x+=this.speedX/damper;
this.y+=this.speedY/damper;
this.speedX*=this.inertia;
this.speedY*=this.inertia;
}
}
function GnodMap()
{
this.aid=null; // aid[i1][i2]: proposed similarity between the two items i1, i2.
this.maxItems=0; // max. number of items to draw. if set to 0, dimension of aid[] is used.
// adjustable constants ------------------------------------------------------
// window size and scaling
this.left =0; // left border of drawing area
this.top =0; // top border of drawing area
this.bottom =0; // bottom border, automatically detected if not set.
this.right =0; // right border, automatically detected if not set.
this.offsetX =0; // x displace central item
this.offsetY =0; // y displace central item
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])
// timing
this.frameDelayInitial=25; // initial value of increasing delay at each timestep
this.slowdownCycle =300; // number of timesteps after that delay is increased
// physics
this.inertia =0.7; // part of velocity kept in one timestep
this.damperInitial =1; // initial value of increasing damper that cool down motion with time
this.damperFactor =1.002; // factor the damper is increased by in one timestep
this.damperMax =100; // max. value of damper
this.springForce0 =0.025; // force between each item and the central item s0 trying to keep them at aid[][]-distance
this.springForce =0.005; // 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.repelDelay =200; // nr. of timesteps without repulsion
this.repelIncrease =0.001; // amount the repelling force that keeps items non overlapping increases each timestep
this.repelMax =0.15; // max amount of repelling force.
this.paddingFactor =1; // factor by which an item is enlarged while avoiding overlap
// ----------------------------------------------------------------------------
var nrItems; // number of items to layout
var maxX, maxY, minX, minY; // bounds of drawing area
var scaleX,scaleY; // scale to make anything fit
var cogX, cogY; // center of gravity of all items
var cycle=0; // refresh cycle counter
var frameDelay; // delay between redraws
var damper; // increasing damper to cool down motion
var repel; // increasing force that repells items to not overlap each other
/**
* update minX,minY,maxX,maxY to window size
* may be overridden by gnodMapSettings
*/
this.updateBoundaries=function()
{
minX=this.left;
minY=this.top;
var haveIE4orNewer = (document.all) ? 1 : 0;
if (haveIE4orNewer)
{
maxX = document.body.clientWidth;
maxY = document.body.clientHeight;
}
else
{
maxX = window.innerWidth;
maxY = window.innerHeight;
}
if (this.right ) maxX=this.right ;
if (this.bottom) maxY=this.bottom;
}
/**
* returns the mean item dimensions (width, height)
*/
this.getMeanItemSize=function()
{
var meanW=0, meanH=0;
for (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)
{
// calculate minimal overlapping
var oMin=positiveMin(Array(oLeft, oRight, oTop, oBottom));
var distance=Math.sqrt(dx*dx+dy*dy);
// repel item in respect to current overlapping
// we assume that dx,dy is a useful direction to decrease the overlapping
var repelScaler=repel*oMin/distance;
item1.x+=dx*repelScaler;
item1.y+=dy*repelScaler;
}
}
/**
* do one layout step.
*/
this.layoutStep=function ()
{
this.layoutItems();
this.recenterItems();
this.updateItems();
if (damperthis.repelDelay && repelthis.slowdownCycle) frameDelay++;
cycle++;
// schedule next layout step
var thisMap=this;
setTimeout(function(){thisMap.layoutStep()},frameDelay);
}
this.sum_of_squared_errors=function()
{
var error0=0, error=0;
for(i1=0; i1needle) high=mid-1;
else if (value0) values.push(this.aid[i][j]);
values.sort();
//assign each aid[][] the rank of its value in values[] normalized to 0.0...1.0
for (var i=0; i0)
{
this.aid[i][j]=1-(search(this.aid[i][j], values)/values.length);
}
}
/**
* initially place every item and start refresh timer.
*/
this.init=function ()
{
// Even though init() gets called on window.onload, in IE it sometimes
// gets started with a screen size of 0. If so, we try again later:
this.updateBoundaries();
if (maxX<1 || maxY<1)
{
setTimeout(function(){gnodMap.init()},500);
return;
}
nrItems=this.aid[0].length;
if (this.maxItems && nrItems>this.maxItems) nrItems=this.maxItems;
this.equalizeAid();
this.resetItemPositions();
setTimeout(function(){gnodMap.layoutStep()},10); // let's go.
}
// ----------------------------------------------------------------------------
// install event handlers.
//
// instead of calling init directy, we attach it to the window.onload event
// especially when the map is loaded, the screensize might not be set
// before that event
var thisMap=this;
window.onload=function()
{
thisMap.init();
}
document.onkeypress=function(event)
{
return thisMap.keyPress(event);
}
window.onresize=function()
{
thisMap.resetItemPositions();
}
}
gnodMap=new GnodMap();
//assign deprecated global settings:
gnodMap.aid=Aid;
gnodMap.maxItems=gnodMapSettings.nrItems;
gnodMap.left =gnodMapSettings.minX;
gnodMap.top =gnodMapSettings.minY;
gnodMap.right =gnodMapSettings.maxX;
gnodMap.bottom =gnodMapSettings.maxY;
gnodMap.offsetX =gnodMapSettings.offsetX;
gnodMap.offsetY =gnodMapSettings.offsetY;
|
|
|
Create a new entry at this position
|
|
|