首先建立一個項目,當前要先在資料庫設定一下。項目說簡單也簡單,說難也難。要用到Ajax與Raphael類庫,不過更多的時候自己舞弄三角函數(做統計這少不了。)
接著刪除public下的index.html,並在routes下添加:
map.root :abilities#★★★★ # Install the default routes as the lowest priority. # Note: These default routes make all actions in every controller accessible via GET requests. You should # consider removing the them or commenting them out if you're using named routes and resources. map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format'
隨便填幾個數值。
前台show.erb用Ajax來調用資料:
<%= javascript_tag "window._token = '#{form_authenticity_token}'" if ActionController::Base.allow_forgery_protection %><%= javascript_include_tag :defaults,"raphael" %><script> window.onload = function(){ var s= '&authenticity_token=' + window._token; var id = window.location.toString().split("/").last(); new Ajax.Request("/abilities/show/"+id, { asynchronous:true, evalScripts:true, method:'post', parameters:s }); }</script><div id="holder"></div><%= link_to 'Edit', edit_ability_path(@ability) %> |<%= link_to 'Back', abilities_path %>
利用Prototype玩Ajax就是這麼簡單。由於Rails2.0中加入了form_authenticity_token來防止部分的cross-site的攻擊,我們需要用一個全域變數來儲存這個東西,然後作為Ajax的一個變數請求回去,防止ActionController::InvalidAuthenticityToken錯誤。
然後在後台添加以下代碼,全部包圍在一個選擇肢中,只有是xhr請求才會調用它們:
主要要點是這是個五邊形,因此我們先用360/5得出得每個點位移的角度,我們通過cos與sin求得每個點的座標。
//以半徑當作三角形的斜邊//斜邊*餘弦得出點投射到X軸的座標//斜邊*正弦得出點投射到Y軸的座標//我們以圓心邊座標系的中心,因此要分別加上圓心的X座標與Y座標 var x=圓心X座標+半徑*Math.cos(-位移的角度)*Math.PI/180) var y=圓心Y座標+半徑*Math.sin(-位移的角度)*Math.PI/180)//角度之所以取負,是因為螢幕的座標系與數學上的座標系是相反的
得出這五個點後,我們用path函數把它們連起來就是,和SVG的用法很相近。最後,後台截獲我們的XHR請求就會完美地產生我們的雷達圖。
var paper=Raphael("holder",400,300),radii=120,cc=[200,150],ability=["認真","聰明","人氣","人品","運氣"],data=[78,90,67,100,80],color={ keynote:"#586F85", circle:"#B3E2D5", bg:"#EEFFEE", edge:"#474747", shadow:"#ABD7CB", light:"#fff", dark:"#000"},circleStyle={ fill:color.circle, stroke:color.edge, "stroke-dasharray":"- "},labelStyle={ fill:color.dark, font:"12px 'Microsoft YaHei',Arial"},outterLabelStyle={ stroke:color.shadow, "stroke-opacity":0.5, "stroke-linecap":"round", "stroke-width":"20px"},frameStyle={ fill:color.light, stroke:color.dark, "stroke-width":1},coords=[];paper.rect(0,0,398,298,10).attr({ fill:color.bg, stroke:color.edge, "stroke-width":"1px"});for(var i=0,n=data.length;i<n;i++){ var x=+(cc[0]+data[i]/100*radii*Math.cos(-(18+72*i)*Math.PI/180)).toFixed(2), y=+(cc[1]+data[i]/100*radii*Math.sin(-(18+72*i)*Math.PI/180)).toFixed(2), el=[x,y], lineX=+(cc[0]+(radii-2)*Math.cos(-(18+72*i)*Math.PI/180)).toFixed(2), lineY=+(cc[1]+(radii-2)*Math.sin(-(18+72*i)*Math.PI/180)).toFixed(2), line=["M",cc[0],cc[1],"L",lineX,lineY,"z"], outX=cc[0]+(radii+20)*Math.cos(-(18+72*i)*Math.PI/180), outY=cc[1]+(radii+20)*Math.sin(-(18+72*i)*Math.PI/180); paper.circle(cc[0],cc[1],radii*(100-20*i)/100).attr(circleStyle); coords.push(el); paper.path(outterLabelStyle,line.join(" ")); paper.text(outX,outY,ability[i]).attr({ "font-size":"14px", "font-weight":700 }).rotate(72-72*i)}var path=["M",coords[0],"L",coords[1],"L",coords[2],"L",coords[3],"L",coords[4],"z"],frame=paper.rect(10,10,55,20,5).attr(frameStyle).hide(),label=paper.text(5,5," ").attr(labelStyle).hide();path=path.join(" ");paper.path({ fill:color.keynote, opacity:0.75, stroke:"none"},path);for(var i=0,n=coords.length;i<n;i++){ var dot=paper.circle(coords[i][0],coords[i][1],5).attr({ fill:color.keynote, opacity:0.95, stroke:"none" }); (function(dot,i){ dot.mouseover(function(){ this.animate({ r:10 },200); frame.show().animate({ x:coords[i][0], y:coords[i][1] },1); label.attr({ text:ability[i]+" "+data[i] }).show().animate({ x:coords[i][0]+25, y:coords[i][1]+10 },1); }); dot.mouseout(function(){ this.animate({ r:5 },200); frame.hide(); label.hide(); }); })(dot,i);}frame.toFront();label.toFront();