新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   >>中国XML论坛<<     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论SVG, GML, X3D, VRML, VML, XAML, AVALON, Batik等基于XML的图形技术,以及有关GIS的应用。
    [返回] 中文XML论坛 - 专业的XML技术讨论区XML.ORG.CN讨论区 - 高级XML应用『 SVG/GML/VRML/X3D/XAML 』 → (转贴)csdn上高手给出的svg例子(画柱状图),老少皆宜,童叟无欺 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 17347 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: (转贴)csdn上高手给出的svg例子(画柱状图),老少皆宜,童叟无欺 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     leomay 帅哥哟,离线,有人找我吗?
      
      
      等级:大二期末(数据结构考了98分!)
      文章:55
      积分:354
      门派:XML.ORG.CN
      注册:2005/2/14

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给leomay发送一个短消息 把leomay加入好友 查看leomay的个人资料 搜索leomay在『 SVG/GML/VRML/X3D/XAML 』的所有贴子 点击这里发送电邮给leomay 引用回复这个贴子 回复这个贴子 查看leomay的博客楼主
    发贴心情 (转贴)csdn上高手给出的svg例子(画柱状图),老少皆宜,童叟无欺

    利用XSLT生成SVG格式的数据统计图

    孟宪会  
    2002-3-18 13:23:33

    --------------------------------------------------------------------------------

    可升级矢量图象(SVG)是新一代的图象标准,它具有矢量化、符合XML规范、可样式单化、文字可搜索、开放源代码等特性,正在逐渐被世界各大计算机软件厂商所支持。由于SVG图象完全符合XML标准,因此,我们就可以利用XSLT来生成SVG图象。下面,我们就某公司一年中的所有产品的月销售额来看看如何利用XSLT来生成SVG格式的数据统计图。数据统计图的样式非常多,有柱状图、饼图、折线图、三维立体效果图等等,我们这里将介绍簇状柱形图、堆积柱形图和饼图。由于篇幅所限,我们这次仅介绍簇状柱形图,我们会在以后文章中介绍其它两种数据统计图的生成方法。
    目前,没有一个浏览器完全支持SVG图象的显示,为了能够看到本例子中效果,您必须安装SVG Viewer 3.0插件,下载地址:http://www.adobe.com/svg/viewer/install/main.html。在Windows XP平台上,自带了Microsoft Internet Explorer 6,但是它是Adobe SVG Viewer 2.0的插件,对中文的支持不好,但可以直接浏览没有中文文字的SVG图象,把本例中的中文换成英文,也可以浏览本例中的代码。我们的例子在支持UTF-16的平台上可以很好地显示,我们就以中文为例。
    首先,我们准备所需要的数据,格式是XML的。由于目前许多大型数据库都提供了对XML查询结果的支持,因此,您可以直接利用数据库来生成XML数据文件,也可以经过查询,再用编写组件的方法来生成需要的XML数据文件。我们的XML数据文件Data.xml格式如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <sales_summary>
    <Month_sales Month_no="1">
    <product_sales product_id="PC_INTEL_001" quantity="5" value="5000.00"/>
    <product_sales product_id="PC_INTEL_002" quantity="10" value="1500.00"/>
    </Month_sales>
    <Month_sales Month_no="2">
    <product_sales product_id="PC_INTEL_001" quantity="4" value="4000.00"/>
    <product_sales product_id="PC_INTEL_002" quantity="10" value="3000.00"/>
    <product_sales product_id="PC_AMD_001" quantity="20" value="1500.00"/>
    <product_sales product_id="PC_AMD_002" quantity="20" value="1800.00"/>
    <product_sales product_id="PC_DIGITAL_001" quantity="11" value="50.00"/>
    <product_sales product_id="PC_DIGITAL_002" quantity="18" value="600.00"/>
    </Month_sales>
    <!-- 限于篇幅所限,我们这里省略了3月份到11月份的数据,如果浏览时,请自行添加上,格式同前 -->
    <Month_sales Month_no="12">
    <product_sales product_id="PC_INTEL_001" quantity="56" value="200.00"/>
    <product_sales product_id="PC_INTEL_002" quantity="10" value="500.00"/>
    <product_sales product_id="PC_AMD_001" quantity="61" value="1500.00"/>
    <product_sales product_id="PC_AMD_002" quantity="8" value="2100.00"/>
    <product_sales product_id="PC_DIGITAL_001" quantity="2" value="500.00"/>
    <product_sales product_id="PC_DIGITAL_002" quantity="6" value="1200.00"/>
    </Month_sales>
    </sales_summary>

    下面,我们看看最关键的XSLT部分,由于在这里用到了XSLT,请把您的MsXML2文件升级到最新的MsXML3.0 SP2或MsXML4.0,可以到微软的网站下载:http://www.microsoft.com/xml/。文中每一代码段都进行了注释说明。XSLTToGraph.xsl:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0"  
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- 定义XSLT转换后输出的文件的格式,这里输出为XML格式的文件内容 -->
    <xsl:output method="xml" indent="yes" encoding="UTF-8" version="1.0" standalone="no" media-type="image/svg+xml"/>
    <!-- 以下定义全局变量 -->
    <!-- 柱状图每个柱的宽度 -->
    <xsl:variable name="bar_width" select="number(80)"/>
    <!-- 每个柱之间的间隔 -->
    <xsl:variable name="bar_spacing" select="number(10)"/>
    <!-- 图象高度 -->
    <xsl:variable name="graph_height" select="number(500)"/>
    <!-- 图象的左边界 -->
    <xsl:variable name="left_margin" select="number(100)"/>

    <xsl:template match="/">
    <!-- SVG的主体部分开始 -->
    <svg id="body" viewBox="0 0 -100 {$graph_height + 100}">
    <!-- 下面的代码实现鼠标的OnMouseOver和OnMouseOut事件执行的代码,显示或隐藏当月的销售额 -->
    <script type="text/ECMAScript"><![CDATA[
    function On_MouseOver(evt,HideShow_ID){
    // 得到目标对象
    var target = evt.getTarget();
    var doc = target.getOwnerDocument();  
    var HideShow = doc.getElementById(HideShow_ID);
    HideShow.setAttribute('style', 'visibility:visible');
    }
    function On_MouseOut(evt,HideShow_ID){
    var target = evt.getTarget();
    var doc = target.getOwnerDocument();
    var HideShow = doc.getElementById(HideShow_ID);
    HideShow.setAttribute('style', 'visibility:hidden');
    }
    ]]></script>
    <title>月销售纪录</title>
    <!-- 柱状图的主体部分 -->
    <g id="barChart" transform="translate(10, 10)" fill-rule="nonzero" clip-rule="nonzero" stroke="none" class="legend"
    stroke-width="1" stroke-linecap="square" stroke-miterlimit="1" style="text-anchor:start" shape-rendering="crispEdges">
    <!-- 应用数据模板 -->
    <xsl:apply-templates select="sales_summary"/>
    <text text-anchor="middle" transform="matrix(2 0 0 2 {$left_margin + 150} {$graph_height + 70})">某公司每月产品销售纪录</text>
    </g>
    </svg>
    </xsl:template>

    <!-- 数据模板开始 -->
    <xsl:template match="sales_summary">
    <!-- 计算月数 -->
    <xsl:variable name="weeks_count" select="count(Month_sales)"/>
    <!-- 计算月最大的销售额 -->
    <xsl:variable name="max_week_sales_value">
    <xsl:for-each select="Month_sales">
    <xsl:sort select="sum(product_sales/@value)" data-type="number" order="descending"/>
    <xsl:if test="position() = 1">
    <xsl:value-of select="sum(product_sales/@value)"/>
    </xsl:if>
    </xsl:for-each>
    </xsl:variable>
    <!-- 柱状图相对高度,圆整为100 -->
    <xsl:variable name="max_graph_height" select="floor(($max_week_sales_value + 99) div 100) * 100"/>
    <!-- 调用模板,画出柱状图的背景及图例文字和边框线 -->
    <xsl:call-template name="draw_graph">
    <xsl:with-param name="max_graph_height" select="$max_graph_height"/>
    <xsl:with-param name="bar_count" select="$weeks_count"/>
    </xsl:call-template>
    <!-- 调用模板,画出柱状图及图例文字 -->
    <xsl:apply-templates select="Month_sales">
    <xsl:sort select="@Month_no" data-type="number"/>
    <xsl:with-param name="max_graph_height" select="$max_graph_height"/>
    </xsl:apply-templates>
    </xsl:template>

    <xsl:template name="draw_graph">
    <xsl:param name="max_graph_height"/>
    <xsl:param name="bar_count"/>
    <xsl:variable name="actual_width" select="($bar_count * ($bar_width + $bar_spacing)) + $bar_spacing"/>
    <g id="GridAndLegend" style="stroke:#00FF00;" shape-rendering="crispEdges" stroke-width="1">
    <!-- 画出背景颜色和边框线 -->
    <path fill="rgb(255, 235, 205)" stroke="#000099" d="M {$left_margin},{$graph_height + 20} h{$actual_width} v-{$graph_height + 10} h-{$actual_width} v{$graph_height +10}"/>
    <!-- 画出原点和水平线 -->
    <path fill="none" stroke="#FF0000" d="M {$left_margin - 10},{$graph_height + 20} h10"/>
    <text text-anchor="end" baseline-shift="-3" transform="matrix(1 0 0 1 {$left_margin - 15} {$graph_height + 20})">0</text>
    <!-- 画出垂直线和图例文字 -->
    <xsl:call-template name="draw_graph_vertical_legends">
    <xsl:with-param name="max" select="$max_graph_height"/>
    <xsl:with-param name="legend_threshold" select="$max_graph_height div $graph_height"/>
    <xsl:with-param name="actual_width" select="$actual_width"/>
    </xsl:call-template>
    </g>
    </xsl:template>

    <!-- 递归调用的模板,画出垂直线和图例说明 -->
    <xsl:template name="draw_graph_vertical_legends">
    <xsl:param name="max"/>
    <xsl:param name="legend_threshold"/>
    <xsl:param name="actual_width"/>
    <!-- 开始数字和步长 -->
    <xsl:param name="start" select="number(100)"/>
    <xsl:param name="step" select="number(100)"/>
    <xsl:param name="prev_marked_start" select="number(0)"/>
    <!-- 计算垂直位置 -->
    <xsl:variable name="prev_vert_posn" select="($prev_marked_start div $max) * $graph_height"/>
    <xsl:variable name="vert_posn" select="($start div $max) * $graph_height"/>
    <!-- 计算本水平线和上一条水平线的间距 -->
    <xsl:variable name="new_marked_start">
    <xsl:choose>
    <xsl:when test="($vert_posn - $prev_vert_posn) >= $legend_threshold">
    <xsl:value-of select="$start"/>
    </xsl:when>
    <xsl:otherwise>
    <xsl:value-of select="$prev_marked_start"/>
    </xsl:otherwise>
    </xsl:choose>
    </xsl:variable>
    <!-- 画出间距不小于一个单位的水平线和图例说明文字 -->
    <xsl:if test="$new_marked_start = $start">
    <path fill="none" stroke="#FF0000" d="M {$left_margin - 10},{$graph_height + 20 - floor($vert_posn)} h{$actual_width + 10}"/>
    <text text-anchor="end" baseline-shift="-3" transform="matrix(1 0 0 1 {$left_margin - 15} {$graph_height + 20 - floor($vert_posn)})">
    <xsl:value-of select="$start"/>
    </text>
    </xsl:if>
    <!-- 如果没有到达最大值,递归调用本模板 -->
    <xsl:if test="$start < $max">
    <xsl:call-template name="draw_graph_vertical_legends">
    <xsl:with-param name="max" select="$max"/>
    <xsl:with-param name="legend_threshold" select="$legend_threshold"/>
    <xsl:with-param name="actual_width" select="$actual_width"/>
    <xsl:with-param name="start" select="$start + $step"/>
    <xsl:with-param name="step" select="$step"/>
    <xsl:with-param name="prev_marked_start" select="$new_marked_start"/>
    </xsl:call-template>
    </xsl:if>
    </xsl:template>

    <!-- 画出每月的销售纪录图 -->
    <xsl:template match="Month_sales">
    <xsl:param name="max_graph_height"/>
    <!-- 画出每月的销售额柱状图,以下三个变量分别代表:当月销售总额、柱的高度、柱的左边坐标位置 -->
    <xsl:variable name="sales_value" select="sum(product_sales/@value)"/>
    <xsl:variable name="bar_height" select="floor(($sales_value div $max_graph_height) * $graph_height)"/>
    <xsl:variable name="bar_left" select="((position() - 1) * ($bar_width + $bar_spacing)) + $bar_spacing"/>
    <!-- 画出柱,并且添加鼠标事件执行的函数 -->
    <path fill="#0066FF" stroke="none" d="M {$bar_left + $left_margin},{$graph_height + 19} h{$bar_width} v-{$bar_height} h-{$bar_width} v{$bar_height}"
    onmouseover="On_MouseOver(evt,'HideShow_{@Month_no}')" onmouseout="On_MouseOut(evt,'HideShow_{@Month_no}')"/>
    <!-- 画出图示说明 -->
    <text text-anchor="middle" transform="matrix(1.5 0 0 1.5 {$left_margin + $bar_left + ($bar_width div 2)} {$graph_height + 40})">
    <xsl:value-of select="@Month_no"/>
    <xsl:text>月</xsl:text>
    </text>
    <!-- 创建鼠标移出时的图样,包括直线和文字 -->
    <g id="HideShow_{@Month_no}" style="visibility: hidden;">
    <!-- 画出水平线 -->
    <path fill="none" stroke="red" d="M {$left_margin - 10},{$graph_height + 20 - $bar_height} h{$bar_left + 10}"/>
    <!-- 写出文字(销售额),并进行格式化 -->
    <text transform="matrix(1 0 0 1 {$left_margin + $bar_left + 2} {($graph_height + 30) - $bar_height})">
    <xsl:value-of select="format-number($sales_value,'#,##0')"/>
    </text>
    </g>
    </xsl:template>
    </xsl:stylesheet>

    最后,要在页面中看到SVG格式的统计图,有两种办法:一是直接在客户端转换,在Data.xml使用XSL样式单即可;二是利用ASP在服务器端先进行转换,再输出到客户端。我们这里采用ASP来完成,因为,如果有多种统计图样式的话,这样可以让用户进行选择显示,调用不同的XSL文件即可。DataToSVG.asp文件如下:

    <%@ Language="VBScript"%>
    <Meta Name="Author" Content="孟宪会">
    <Meta Name="WebSite" Content="http://lucky.myrice.com">
    <Meta Name="WebSite" Content="http://www.ccw.com.cn">
    <Meta Name="CopyRight" Content="【孟宪会之精彩世界】,《计算机世界》网">
    <%
    Response.Clear
    Response.Buffer = True
    Dim xmlDom, xslDom, strResult
    Set xmlDom = Server.CreateObject("Msxml2.DOMDocument")
    Set xslDom = Server.CreateObject("Msxml2.FreeThreadedDOMDocument")
    xmlDom.async = False
    xslDom.async = False

    xmlDom.load Server.MapPath("Data.xml")
    xslDom.load Server.MapPath("XSLTToGraph.xsl")
    Response.ContentType = "image/svg+xml"

    strResult = xmlDom.transformNode(xslDom)
    ' 在不支持UTF-16编码的饿平台上,替换成UTF-8
    strResult = Replace(strResult,"UTF-16","UTF-8")
    Response.Write strResult
    %>  

    结果如下图:




    此主题相关图片如下:
    按此在新窗口浏览图片


       收藏   分享  
    顶(0)
      




    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/6/17 9:05:00
     
     xiaoyubujimo 帅哥哟,离线,有人找我吗?
      
      
      等级:大一新生
      文章:0
      积分:56
      门派:XML.ORG.CN
      注册:2005/10/15

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给xiaoyubujimo发送一个短消息 把xiaoyubujimo加入好友 查看xiaoyubujimo的个人资料 搜索xiaoyubujimo在『 SVG/GML/VRML/X3D/XAML 』的所有贴子 引用回复这个贴子 回复这个贴子 查看xiaoyubujimo的博客2
    发贴心情 
    恩,我感觉XML的语法好复杂
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/10/19 14:25:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 SVG/GML/VRML/X3D/XAML 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/4/28 8:47:58

    本主题贴数2,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    78.125ms