[JS]Canvasを使って、リアルタイムにヒートマップを描くスクリプト -real time heatmap
Post on:2010年10月26日
ユーザーのマウスの動きに伴い、リアルタイムにヒートマップを生成するスクリプトを紹介します。
[ad#ad-2]
デモの画像の上でマウスを動かすと、その動いた量に伴いカラーがブルー、グリーン、イエロー、レッドとマウスの移動し滞在した量をヒートマップとして生成します。ヒートマップのデータはエクスポートも可能です。
また、iPhoneのシングルタップもサポートしている、とのことです。
スクリプトはjQueryなどの他のスクリプトは依存せず、下記のようになります。
JavaScirpt
/* Copyright (c) 2010, Patrick Wied. All rights reserved. Code licensed under the BSD License: http://patrick-wied.at/static/license.txt */ var heatmapApp = (function(){ // var definition // canvas: the canvas element // ctx: the canvas 2d context // width: the heatmap width for border calculations // height: the heatmap height for border calculations // invoke: the app doesn't react on the mouse events unless the invoke var is set to true var canvas, ctx, width, height, radius1 = 20, radius2 = 40, invoke = false, // function for coloring the heatmap colorize = function(x,y,x2){ // initial check if x and y is outside the app // -> resetting values 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 = ctx.getImageData(x,y,x2,x2), // some performance tweaks imageData = image.data, length = imageData.length; // loop thru the area for(var i=3; i < length; i+=4){ var r = 0, g = 0, b = 0, tmp = 0, // [0] -> r, [1] -> g, [2] -> b, [3] -> alpha alpha = imageData[i]; // coloring depending on the current alpha value if(alpha<=255 && alpha >= 235){ tmp=255-alpha; r=255-tmp; g=tmp*12; }else if(alpha<=234 && alpha >= 200){ tmp=234-alpha; r=255-(tmp*8); g=255; }else if(alpha<= 199 && alpha >= 150){ tmp=199-alpha; g=255; b=tmp*5; }else if(alpha<= 149 && alpha >= 100){ tmp=149-alpha; g=255-(tmp*5); b=255; }else b=255; // we ve started with i=3 // set the new r, g and b values imageData[i-3]=r; imageData[i-2]=g; imageData[i-1]=b; } // 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); }, // this handler is listening to the mouse movement of the user mouseMoveHandler = function(ev){ // if the invoke variable is set to true -> do the alphamap manipulation if(invoke){ // at first we have to get the x and y values of the user's mouse position 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; // storing the variables because they will be often used var r1 = radius1; var r2 = radius2; //console.log("x: "+x+"; y:" +y); // create a radial gradient with the defined parameters. we want to draw an alphamap var rgr = ctx.createRadialGradient(x,y,r1,x,y,r2); // the center of the radial gradient has .1 alpha value rgr.addColorStop(0, 'rgba(0,0,0,0.1)'); // and it fades out to 0 rgr.addColorStop(1, 'rgba(0,0,0,0)'); // drawing the gradient ctx.fillStyle = rgr; ctx.fillRect(x-r2,y-r2,2*r2,2*r2); // negate the invoke variable // next execution of the logic is when the activate method activates the invoke var again invoke=!invoke; // at least colorize the area colorize(x-r2,y-r2,2*r2); } }, // we don't want to capture all events because this would result in low performance // -> a function for activating the heatmap logic which will be called in a specified interval activate = function(){ invoke = !invoke; }; return { // initialization initialize: function(c, wt, ht){ canvas = document.getElementById(c); canvas.width = wt; canvas.height = ht; canvas.style.border = "2px solid black"; ctx = canvas.getContext("2d"); width = wt; height = ht; canvas["onmousemove"] = function(ev){ mouseMoveHandler(ev); }; // iPhone / iPad support canvas["ontouchmove"] = function(ev){ var touch = ev.touches[0], // simulating a mousemove event simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent("mousemove", true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); // dispatching the simulated event touch.target.dispatchEvent(simulatedEvent); // we don't want to have the default iphone scrolling behaviour ontouchmove ev.preventDefault(); }; // call the activate function in an interval of 50ms (function(fn){ setInterval(fn, 50); })(activate); }, // if you like to process the image data e.g onbeforeunload // just call the getData method -> returns imagedata as a dataurl string getData: function(){ return canvas.toDataURL(); } }; })(); window["onload"]=function(){ //call the initialization heatmapApp.initialize("c",300,900); }
ライセンスはBSD Licenseとのことです。
sponsors