Follow @Ibrahim
Tweet
BLOB.jsv1.0.4.2
A tiny javascript library for drawing blobs...
Blob.js is a work on progress, I modify it as needed for other projects. As new stuff is added, I try to gather them in separate pages. Below are the quick links:
INTRODUCTION RENDERING SHAPES
For the ones that don't know what I work on, well its Malformations of Cortical Development.
I was thinking to simulate migrating neurons. I thought of a simple concept: points radially distributed around a focal point doing harmonic motion. The origin would resemble a centriole, with microtubule extensions. All sorts of shapes and object can be drawn by this simple way describing motion. So I thought why not release it..
Let's see some examples. First include the script in your heading:
script src="http://i-pv.org/js/blob1.0.4.2.js" type="text/javascript. It will initiate 3 GLOBAL variables: coordinates([x,y]),areaBlob({..}) and blobJsCanvasCounter(incremented variable). Then initiate a drawing area: initiateBlobArea({id:"drawHere2",width:500,height:500,top:1300,left:700})





Don't see anything yet but it is there. Now time to draw something:
blob({nodeCount:7,origin:[250,125],blobRadius:50,lineWidth:200,strokeStyle:"orange",fillStyle:"orange",
randomness:0,fillOpacity:0.6,lineOpacity:1,minPeriod:2,maxPeriod:5,id:"myFirstBlob",
harmonicRadius:6,attraction:0.5,bounce:1,xray:0,});







So simply pass an object to blob function. If a field does not exist, than a default value is used. Here are the possible fields and what they change:
parent: OPTIONAL. This field exists both for initiateBlobArea() and blob() functions. If present, the element will be added under the element with the specified ID. ex:{..,parent:"IdofParent"}. If not present element is added under body.
nodeCount: the amount of nodes to set in motion.
origin: an array designating the origin of the shape, taking 0,0 as the initated area.
maxPeriod/minPeriod: period limits of the points oscilliating.
blobRadius: radius of the blob, in pixels.
tickRadius: the width of the ticks, in pixels.
harmonicRadius: the span of each point, in pixels.
sync: on by default, if you make it -1 than the shape will oscilliate left to right even when the max/min periods are the same.
randomness: multiplies each blob radius by a random coefficient, values between 0 and 0.5, 0 by default, do not exceed over 0.5.
bounceSpeed: default value 0.975, maximum 1. Bigger values makes the bounce effect SLOWER.
lineWidth: width of the line surrounding the shape, in pixels.
lineOpacity: values between 0 and 1.
fillOpacity: values between 0 and 1.
strokeStyle: color of the line. You can use html colors. Provide STRING.
fillStyle: color of the inner filling. You can use html colors. Provide STRING.
attraction: 0.5 by default. If present, the blob is attracted towards mouse pointer position. To remove mouse responsiveness, provide a number sufficiently close to zero such as 0.0001. Negative values repel the blob instead. Do not exceed |0.5|.
bounce: default value 1. The blob gets a bounce effect when the mouse is sufficiently close OR far. Set to -1 to turn it off, NOT ZERO.
xray: Turns on the guide lines so you can trace the points of the blob. A bit of data visualization :) The green and the red blob at the top of this page has this field set to 1.
parameter: OPTIONAL. Provide a function that will be evaluated ONCE for EACH of the nodes of a blob when starting its animation. Allowed variables are the nodeCount and the i which is iterated for EACH node. For instance the sea star on the top right corner of this page has a parameter of: 0.4+0.6*Math.abs(Math.pow(Math.sin(5*Math.PI*i/nodeCount-Math.PI/2),3)). If you change the 5 to another value than the shape will have that many vertices or extensions or whatever you want to name them. Just make sure the number you enter is divisible by your nodeCount. If you want to rotate it, than subtract a value in RADIANS within the sine function bracket. If you want to make the blob sharper, increase the power value.
Now, you can do a lot without the parameter, which is set to 1 by default. I will now use this parameter to draw a water droplet:








The droplet on the left has a parameter of:
function(i,nodeCount){return 0.75+(4*Math.pow((i-nodeCount/4)/nodeCount,2))*Math.round(0.75-i/nodeCount)+Math.round(i/(1.5*nodeCount))*(4*Math.pow((i-nodeCount/4*3)/nodeCount,2));}.
The 2nd droplet from left, has an additional randomness parameter of 0.3 and looks like a brittle leaf. The third droplet has randomness 0 but the minPeriod and maxPeriod parameters changed to 5 and 6 instead of 4 and 4, it looks bit like a cell. The last droplet on right is almost the same as the first, but it has the xray parameter set to 1 and the parameter is slightly changed:
function(i,nodeCount){return 0.75+(4*Math.pow((Math.abs(i-5)-nodeCount/4)/nodeCount,2))*Math.round(0.75-Math.abs(i-5)/nodeCount)+Math.round(Math.abs(i-5)/(1.5*nodeCount))*(4*Math.pow((Math.abs(i-5)-nodeCount/4*3)/nodeCount,2));}
The only difference is that the i is replaced by Math.abs(i-5) to give it a rotation of pi/3 radians (nodeCount was 30, subtracted value is 5 so 5/30*360 = 60 degrees/~1.05 radians).









The above example is a demonstration of how you can cover a surface with hexagons like in the I-PV webpage. Once again initiate a drawing surface: initiateBlobArea({id:"drawHere5",width:640,height:240,top:4400,left:650});. Then use the following code:
for (var k=0;k < 4;k++){
for (var j=0;j < 10;j++){
var color = ["Orange","Green","Gold","Pink","Red","Purple","DodgerBlue","Orange"][Math.floor(Math.random()*7)];
blob({nodeCount:6,origin:[0+j*80-(k%2)*40,0+k*60+30],blobRadius:35,lineWidth:0.01,strokeStyle:color,fillStyle:color, randomness:0,fillOpacity:0.5,lineOpacity:0.8,minPeriod:3,maxPeriod:3,id:"myCanvas",harmonicRadius:5, attraction:0.0001,bounce:1,xray:0});

}
}
You can already use this for a funny way to visualize data without using parameters or anything. First declare an array of 40 random x,y pairs outside the for loops:
var myVariables = [Math.random(),Math.random()];
Make the width bit larger (odd rows in the hexogons above lack 1 hexagon, because it is hidden on the left). In the above code, just where you declare the color for each canvas element, declare 4 new variables based on how far away 2 random x,y pairs are:
var diff = Math.abs(myVariables[k*10+j][0]-myVariables[k*10+j][1]);
var color = ["red","green","blue","darkblue"][Math.round(diff*3)];
var blobRadius = 20+15*diff;
var harmonicRadius = 2+3*diff;
var periods = 3-2*diff;
Now, instead of writing blobRadius:35 and harmonicRadius: 5 in the object you pass to blob function, pass the above variables. Below is the result when these 5 lines are added to the inner for loop:










There is one more field for the blob function worth mentioning, parameterTime(). It is very similar to parameter() but at the same time very different:
parameterTime: OPTIONAL. Provide a function that will be executed for EACH node at EACH frame. Takes 3 arguments, i, nodeCount and time (total elapsed animation time in seconds). If not present returns 1.
Both parameterTime() and parameter() change the node radius. They are mutually exclusive, so there is not much reason to use parameterTime() when parameter() can be sufficient. However, I will give a quick example of how parameterTime() differs.
Take the code of the sea star at the top of the page:
blob({nodeCount:25,origin:[680,80],
blobRadius:60,lineWidth:28,strokeStyle:"red",
fillStyle:"orange",randomness:0,
fillOpacity:0.5,lineOpacity:0.75,minPeriod:4,
maxPeriod:6,id:"myCanvas",harmonicRadius:4,
attraction:0.5,parameter:
function(i,nodeCount){
return 0.4+0.6*Math.abs(Math.pow(Math.sin(5*Math.PI*i/nodeCount-Math.PI/2),3));},bounce:1,xray:1});

Instead of parameter field, write this one:
parameterTime:function(i,nodeCount,t){
var time = t*1000;
return 0.7+0.3*Math.abs(
Math.pow(
Math.sin(
9*Math.PI*i/nodeCount-Math.PI/2-((time%4000)/4000*Math.PI*2)
)
,9)
);}

These will look like gears with 0.001 fillOpacity. Change the nodeCounts to 45. Place two gears sufficently close to each other and remove an extra 1/9*PI radians ( since there is 9 tooth in the gear) from the right one, turn on the xray field, reduce attractions to 0.0001, change the function of the right gear so its Δ angle increases similar to y=x^1/2 and this is the result:








Experiment with the paramer function and the other fields, you might come accross some interesting effects. Make sure that the initiated drawing area is under the same parent of the canvas elements. By default drawing area has a background of null. Instead you should add your background separately with the smallest z index such as -1000. Your z-index order should be drawing area > canvas elements > custom background.
If you are planning to make an animation while something is working in the background in your code, you can call your custom function to remove the canvas elements and the drawing area with document.getElementById("parentID").removeChild("canvasElemID") method.
I might later on add other functionalities as well as mobile support, touch events and etc. But the main idea is there. If you want to ask anything, just head back to http://i-pv.org/aboutMe.html.
Ibrahim Tanyalcin