用Raphael绘制雷达图(radar chart)

首先新建一个项目,当前要先在数据库设置一下。项目说简单也简单,说难也难。要用到Ajax与Raphael类库,不过更多的时候自己舞弄三角函数(做统计这少不了。)

o_chart1.gif
o_chart2.gif

接着删除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'

随便填几个数值。

o_chart3.gif

前台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请求才会调用它们:

o_chart4.gif
o_chart5.gif
o_chart6.gif
o_chart7.gif
o_chart8.gif

主要要点是这是个五边形,因此我们先用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请求就会完美地生成我们的雷达图。

o_chart9.gif

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();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值