以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 SVG/GML/VRML/X3D/XAML 』  (http://bbs.xml.org.cn/list.asp?boardid=21)
----  请教svg曲线图  (http://bbs.xml.org.cn/dispbbs.asp?boardid=21&rootid=&id=41065)


--  作者:agan
--  发布时间:12/11/2006 9:24:00 AM

--  请教svg曲线图
我想用.net生成svg曲线图,没找到这方面的资料,直方图跟饼图有,哪位做过能给个小例子看看,谢了!
QQ:178266914
E_Mail:lkwjl@sina.com
--  作者:wenwu2008
--  发布时间:12/11/2006 10:44:00 AM

--  
我用过GDI+里面的GraphicsPath类,从那里面再转成SVG的path元素,会比较简单。只是我转弧形时,算的比较复杂。我把代码发上来吧。
 public:
   //将一个SVG中的扇形转成一个Graphics中的扇形,x_axis_rotation代表长半短轴顺时针旋转的角度,large_arc_flag代表是在圆还是小圆,sweep_flag代表是顺时针还是逆时针转动。
   //假设存在严格匹配的扇形,不需要移动长半轴和短半轴
   static void SVGArcToGDI(Drawing::Drawing2D ::GraphicsPath ^tagPath,Drawing::PointF startPoint,Drawing::PointF overPoint,float rx,float ry,float x_axis_rotation,float large_arc_flag,float sweep_flag)
   {
    //第一次解会得到
    double t=2*(overPoint.Y -startPoint.Y)/ry;
    double V=Math::Pow (((overPoint.Y-startPoint.Y )/ry),2)+(overPoint.X*overPoint.X-startPoint.X*startPoint.X ) /(rx*rx);

    //方程的三个系数
    double A=4*Math::Pow ((startPoint.X-overPoint.X ),2)/Math::Pow (rx,4)+t*t/(rx*rx);
    double B=4*(startPoint.X -overPoint.X )*V/(rx*rx)-t*t*2*startPoint.X /(rx*rx);
    double C=V*V-t*t*(1-startPoint.X *startPoint.X /(rx*rx));
    //得解为椭圆的中心点,
    double PX_1,PY_1,PX_2,PY_2;
    //当半径不够时,扩大半径,以达到拟合.
    while(B*B-4*A*C<0)
    {
     rx*=1.01F;
     ry*=1.01F;
     V=Math::Pow (((overPoint.Y-startPoint.Y )/ry),2)+(overPoint.X*overPoint.X-startPoint.X*startPoint.X ) /(rx*rx);
     A=4*Math::Pow ((startPoint.X-overPoint.X ),2)/Math::Pow (rx,4)+t*t/(rx*rx);
     B=4*(startPoint.X -overPoint.X )*V/(rx*rx)-t*t*2*startPoint.X /(rx*rx);
     C=V*V-t*t*(1-startPoint.X *startPoint.X /(rx*rx));
    }
    if(B*B-4*A*C>0)
    {
     //第一组
     PX_1=((0-B)+Math::Pow ((B*B-4*A*C),0.5))/(2*A);
     PY_1=startPoint.Y -ry*Math::Pow ((1- Math::Pow ((startPoint.X -PX_1),2)/(rx*rx) ),0.5);
     if(Math::Abs ((Math::Pow ((overPoint.X -PX_1)/rx,2)+Math::Pow ((overPoint.Y -PY_1)/ry,2))-1)>0.00001)
      PY_1=startPoint.Y +ry*Math::Pow ((1- Math::Pow ((startPoint.X -PX_1),2)/(rx*rx) ),0.5);
     //第二组

     PX_2=((0-B)-Math::Pow ((B*B-4*A*C),0.5))/(2*A);
     PY_2=startPoint.Y -ry*Math::Pow ((1- Math::Pow ((startPoint.X -PX_2),2)/(rx*rx) ),0.5);
     if(Math::Abs ((Math::Pow ((overPoint.X -PX_2)/rx,2)+Math::Pow ((overPoint.Y -PY_2)/ry,2))-1)>0.00001)
      PY_2=startPoint.Y +ry*Math::Pow ((1- Math::Pow ((startPoint.X -PX_2),2)/(rx*rx) ),0.5);
    }
    else
    {
     if(B*B-4*A*C==0)
     {
      PX_1=((0-B)+Math::Pow ((B*B-4*A*C),0.5))/(2*A);
      PX_2=PX_1;
      PY_1=startPoint.Y -ry*Math::Pow ((1- Math::Pow ((startPoint.X -PX_1),2)/(rx*rx) ),0.5);
      PY_2=startPoint.Y +ry*Math::Pow ((1- Math::Pow ((startPoint.X -PX_1),2)/(rx*rx) ),0.5);
      if(Math::Abs ((Math::Pow ((overPoint.X -PX_2)/rx,2)+Math::Pow ((overPoint.Y -PY_2)/ry,2))-1)>0.00001)
       PY_2=PY_1;
      if(Math::Abs ((Math::Pow ((overPoint.X -PX_1)/rx,2)+Math::Pow ((overPoint.Y -PY_1)/ry,2))-1)>0.00001)
       PY_1=PY_2;
      //判断PY_2是否合理,如合理则继续,否则PY_2=PY_1;
     }
    }
    Drawing::PointF P1=Drawing::PointF (Convert::ToSingle (PX_1),Convert::ToSingle (PY_1));
    Drawing::PointF P2=Drawing::PointF (Convert::ToSingle (PX_2),Convert::ToSingle (PY_2));
    Drawing::PointF center;
    //为了判断四种情况,需要计算,先判断中心点在直线的左边还是右边
    double k=(P1.X -startPoint.X )*(overPoint.Y-P1.Y)-(overPoint.X-P1.X )*(P1.Y -startPoint.Y );
    if(large_arc_flag+sweep_flag==0||large_arc_flag+sweep_flag==2)//在左边
     if(k>0)
      center=Drawing::PointF (P1.X ,P1.Y );
     else
      center=Drawing::PointF (P2.X ,P2.Y );
    else
     if(k>0)
      center=Drawing::PointF (P2.X ,P2.Y );
     else
      center=Drawing::PointF (P1.X ,P1.Y );
    //得到center为最终椭圆中心
    //求两点在椭圆上的位置
    //求开始点所在的角度,确保结果大于0度
    double dx=center.X -startPoint.X ;
    double dy=center.Y -startPoint.Y ;
    double startAngle=Math::Asin(dy/Math::Pow ((dx*dx+dy*dy),0.5))*180/Math::PI ;
    if(dx>=0)
     startAngle=180-startAngle;
    else
     if(dy<0)
      startAngle+=360; 
    startAngle=360-startAngle;
    //求终点所在的角度
    dx=center.X -overPoint.X ;
    dy=center.Y -overPoint.Y ;
    double overAngle=Math::Asin(dy/Math::Pow ((dx*dx+dy*dy),0.5))*180/Math::PI ;
    if(dx>=0)
     overAngle=180-overAngle;
    else
     if(dy<0)
      overAngle+=360;    
    overAngle=360-overAngle;
    //如果是逆时钟,交换起末点
    double swepAngle=overAngle-startAngle;
    if(sweep_flag==0)
    {
     if(swepAngle>0)
      swepAngle=0-swepAngle;
    }
    else
    {
     if(swepAngle<0)
      swepAngle=0-swepAngle;
    }
    //必须保证弧的起点不变,可以使用转过负角来达到要求
    tagPath->AddArc (center.X -rx,center.Y-ry,rx*2,ry*2,Convert::ToSingle (startAngle),Convert::ToSingle (swepAngle));      
   }


--  作者:agan
--  发布时间:12/11/2006 11:06:00 AM

--  
有折线图的没有?可以线考虑不用转换成曲线的,有的话能给我发个小例子吗?从哪里取数据到是无所谓,现在没有头绪。。。
--  作者:tamefox
--  发布时间:12/16/2006 10:14:00 AM

--  
其实用SVG画图,无论是饼图、折线图什么的,原理都一样。折线图相对更简单一些,你可以用类似<polyline points="100 100 200 150 300 90 400 70" fill="none" stroke="red"/>这样的语句绘制每条折线。points中的点对中的x、y坐标对应你相应的X轴和y轴的值即可
W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
1,546.875ms