Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * heatmap.js 1.0 - JavaScript Heatmap Library
- *
- * Copyright (c) 2011, Patrick Wied (http://www.patrick-wied.at)
- * Dual-licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
- * and the Beerware (http://en.wikipedia.org/wiki/Beerware) license.
- */
- (function(w){
- // the heatmapFactory creates heatmap instances
- var heatmapFactory = (function(){
- // store object constructor
- // a heatmap contains a store
- // the store has to know about the heatmap in order to trigger heatmap updates when datapoints get added
- function store(hmap){
- var _ = {
- // data is a two dimensional array
- // a datapoint gets saved as data[point-x-value][point-y-value]
- // the value at [point-x-value][point-y-value] is the occurrence of the datapoint
- data: [],
- // tight coupling of the heatmap object
- heatmap: hmap
- };
- // the max occurrence - the heatmaps radial gradient alpha transition is based on it
- this.max = 0;
- this.get = function(key){
- return _[key];
- },
- this.set = function(key, value){
- _[key] = value;
- };
- };
- store.prototype = {
- // function for adding datapoints to the store
- // datapoints are usually defined by x and y but could also contain a third parameter which represents the occurrence
- addDataPoint: function(x, y){
- if(x < 0 || y < 0)
- return;
- var heatmap = this.get("heatmap"),
- data = this.get("data");
- if(!data[x]) data[x] = [];
- if(!data[x][y]) data[x][y] = 1;
- // if count parameter is set increment by count otherwise by 1
- data[x][y]+=(arguments.length<3)?1:arguments[2];
- // do we have a new maximum?
- if(this.max < data[x][y]){
- this.max = data[x][y];
- // max changed, we need to redraw all existing(lower) datapoints
- heatmap.get("actx").clearRect(0,0,heatmap.get("width"),heatmap.get("height"));
- for(var one in data)
- for(var two in data[one])
- heatmap.drawAlpha(one, two, data[one][two]);
- // @TODO
- // implement feature
- // heatmap.drawLegend(); ?
- return;
- }
- heatmap.drawAlpha(x, y, data[x][y]);
- },
- setDataSet: function(obj){
- this.max = obj.max;
- var heatmap = this.get("heatmap"),
- data = this.get("data"),
- d = obj.data,
- dlen = d.length;
- // clear the heatmap before the data set gets drawn
- heatmap.clear();
- while(dlen--){
- var point = d[dlen];
- heatmap.drawAlpha(point.x, point.y, point.count);
- if(!data[point.x]) data[point.x] = [];
- if(!data[point.x][point.y]) data[point.x][point.y] = 1;
- data[point.x][point.y]+=point.count;
- }
- },
- exportDataSet: function(){
- var data = this.get("data");
- var exportData = [];
- for(var one in data){
- // jump over undefined indexes
- if(one === undefined)
- continue;
- for(var two in data[one]){
- if(two === undefined)
- continue;
- // if both indexes are defined, push the values into the array
- exportData.push({x: parseInt(one, 10), y: parseInt(two, 10), count: data[one][two]});
- }
- }
- return exportData;
- },
- generateRandomDataSet: function(points){
- var heatmap = this.get("heatmap"),
- w = heatmap.get("width"),
- h = heatmap.get("height");
- var randomset = {},
- max = Math.floor(Math.random()*1000+1);
- randomset.max = max;
- var data = [];
- while(points--){
- data.push({x: Math.floor(Math.random()*w+1), y: Math.floor(Math.random()*h+1), count: Math.floor(Math.random()*max+1)});
- }
- randomset.data = data;
- this.setDataSet(randomset);
- }
- };
- // heatmap object constructor
- function heatmap(config){
- // private variables
- var _ = {
- radiusIn : 20,
- radiusOut : 40,
- zoom: 1,
- element : {},
- canvas : {},
- acanvas: {},
- ctx : {},
- actx : {},
- visible : true,
- width : 0,
- height : 0,
- max : false,
- gradient : false,
- opacity: 180
- };
- // heatmap store containing the datapoints and information about the maximum
- // accessible via instance.store
- this.store = new store(this);
- this.get = function(key){
- return _[key];
- },
- this.set = function(key, value){
- _[key] = value;
- };
- // configure the heatmap when an instance gets created
- this.configure(config);
- // and initialize it
- this.init();
- };
- // public functions
- heatmap.prototype = {
- configure: function(config){
- if(config.radius){
- var rout = config.radius,
- rin = parseInt(rout/2);
- }
- this.set("radiusIn", rin || 15),
- this.set("radiusOut", rout || 40),
- this.set("element", (config.element instanceof Object)?config.element:document.getElementById(config.element));
- this.set("visible", config.visible);
- this.set("max", config.max || false);
- this.set("gradient", config.gradient || { 0.45: "rgb(0,0,255)", 0.55: "rgb(0,255,255)", 0.65: "rgb(0,255,0)", 0.95: "yellow", 1.0: "rgb(255,0,0)"}); // default is the common blue to red gradient
- this.set("opacity", parseInt(255/(100/config.opacity), 10) || 180);
- this.set("width", config.width || 0);
- this.set("height", config.height || 0);
- if(config.palette != undefined){
- // this.set("gradient", config.palette);
- }
- },
- init: function(){
- this.initColorPalette();
- var canvas = document.createElement("canvas"),
- acanvas = document.createElement("canvas"),
- element = this.get("element");
- this.set("canvas", canvas);
- this.set("acanvas", acanvas);
- canvas.width = acanvas.width = element.style.width.replace(/px/,"") || this.getWidth(element);
- this.set("width", canvas.width);
- canvas.height = acanvas.height = element.style.height.replace(/px/,"") || this.getHeight(element);
- this.set("height", canvas.height);
- canvas.style.position = acanvas.style.position = "absolute";
- canvas.style.top = acanvas.style.top = "0";
- canvas.style.left = acanvas.style.left = "0";
- canvas.style.zIndex = 1000000;
- if(!this.get("visible"))
- canvas.style.display = "none";
- this.get("element").appendChild(canvas);
- this.set("ctx", canvas.getContext("2d"));
- this.set("actx", acanvas.getContext("2d"));
- },
- initColorPalette: function(){
- var canvas = document.createElement("canvas");
- canvas.width = "1";
- canvas.height = "256";
- var ctx = canvas.getContext("2d");
- var grad = ctx.createLinearGradient(0,0,1,256),
- gradient = this.get("gradient");
- for(var x in gradient){
- grad.addColorStop(x, gradient[x]);
- }
- ctx.fillStyle = grad;
- ctx.fillRect(0,0,1,256);
- this.set("gradient", ctx.getImageData(0,0,1,256).data);
- delete canvas;
- delete grad;
- delete ctx;
- },
- getWidth: function(element){
- var width = element.offsetWidth;
- if(element.style.paddingLeft)
- width+=element.style.paddingLeft;
- if(element.style.paddingRight)
- width+=element.style.paddingRight;
- return width;
- },
- getHeight: function(element){
- var height = element.offsetHeight;
- if(element.style.paddingTop)
- height+=element.style.paddingTop;
- if(element.style.paddingBottom)
- height+=element.style.paddingBottom;
- return height;
- },
- colorize: function(x, y){
- // get the private variables
- var width = this.get("width"),
- radiusOut = this.get("radiusOut"),
- height = this.get("height"),
- actx = this.get("actx"),
- ctx = this.get("ctx");
- var x2 = radiusOut*2;
- if(x+x2>width)
- x=width-x2;
- if(x<0)
- x=0;
- if(y<0)
- y=0;
- if(y+x2>height)
- y=height-x2;
- // get the image data for the mouse movement area
- var image = actx.getImageData(x,y,x2,x2),
- // some performance tweaks
- imageData = image.data,
- length = imageData.length,
- palette = this.get("gradient"),
- opacity = this.get("opacity");
- // loop thru the area
- for(var i=3; i < length; i+=4){
- // [0] -> r, [1] -> g, [2] -> b, [3] -> alpha
- var alpha = imageData[i],
- offset = alpha*4;
- if(!offset)
- continue;
- // we ve started with i=3
- // set the new r, g and b values
- imageData[i-3]=palette[offset];
- imageData[i-2]=palette[offset+1];
- imageData[i-1]=palette[offset+2];
- // we want the heatmap to have a gradient from transparent to the colors
- // as long as alpha is lower than the defined opacity (maximum), we'll use the alpha value
- imageData[i] = (alpha < opacity)?alpha:opacity;
- }
- // the rgb data manipulation didn't affect the ImageData object(defined on the top)
- // after the manipulation process we have to set the manipulated data to the ImageData object
- image.data = imageData;
- ctx.putImageData(image,x,y);
- },
- drawAlpha: function(x, y, count){
- // storing the variables because they will be often used
- var r1 = this.get("radiusIn"),
- r2 = this.get("radiusOut"),
- ctx = this.get("actx"),
- max = this.get("max"),
- // create a radial gradient with the defined parameters. we want to draw an alphamap
- rgr = ctx.createRadialGradient(x,y,r1,x,y,r2),
- xb = x-r2, yb = y-r2, mul = 2*r2;
- // the center of the radial gradient has .1 alpha value
- rgr.addColorStop(0, 'rgba(0,0,0,'+((count)?(count/this.store.max):'0.1')+')');
- // and it fades out to 0
- rgr.addColorStop(1, 'rgba(0,0,0,0)');
- // drawing the gradient
- ctx.fillStyle = rgr;
- ctx.fillRect(xb,yb,mul,mul);
- // finally colorize the area
- this.colorize(xb,yb);
- },
- toggleDisplay: function(){
- var visible = this.get("visible"),
- canvas = this.get("canvas");
- if(!visible)
- canvas.style.display = "block";
- else
- canvas.style.display = "none";
- this.set("visible", !visible);
- },
- // Hide canvas
- hide: function(){
- canvas = this.get("canvas");
- canvas.style.display = "none";
- this.set("visible", false);
- },
- // Display the canvas
- show: function(){
- canvas = this.get("canvas");
- canvas.style.display = "block";
- this.set("visible", true);
- },
- // dataURL export
- getImageData: function(){
- return this.get("canvas").toDataURL();
- },
- changeZoom: function(scale){
- var zoom = this.get("zoom");
- var ctx = this.get("ctx");
- var width = this.get("width");
- var height = this.get("height");
- var newWidth = width * scale;
- var newHeight = height * scale;
- ctx.save();
- ctx.translate(-((newWidth-width)/2), -((newHeight-height)/2));
- ctx.scale(scale, scale);
- ctx.clearRect(0, 0, width, height);
- ctx.drawImage(copiedCanvas, 0, 0);
- ctx.restore();
- },
- clear: function(){
- var w = this.get("width"),
- h = this.get("height");
- this.store.set("data",[]);
- // @TODO: reset stores max to 1
- //this.store.max = 1;
- this.get("ctx").clearRect(0,0,w,h);
- this.get("actx").clearRect(0,0,w,h);
- },
- destroy: function(){
- var element = this.get("element");
- var canvas = this.get("canvas");
- // this.get("element").removeNode(true);
- element.removeChild(canvas);
- // this.get("canvas").removeNode(true);
- }
- };
- return {
- create: function(config){
- return new heatmap(config);
- },
- util: {
- mousePosition: function(ev){
- // this doesn't work right
- // rather use
- /*
- // this = element to observe
- var x = ev.pageX - this.offsetLeft;
- var y = ev.pageY - this.offsetTop;
- */
- var x, y;
- if (ev.layerX) { // Firefox
- x = ev.layerX;
- y = ev.layerY;
- } else if (ev.offsetX) { // Opera
- x = ev.offsetX;
- y = ev.offsetY;
- }
- if(typeof(x)=='undefined')
- return;
- return [x,y];
- }
- }
- };
- })();
- w.h337 = w.heatmapFactory = heatmapFactory;
- })(window);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement