SVG 与 XML 商业图表实务

运用 Adobe 的 SVG 技术从 XML 数据创建漂亮的商业图像

学习如何使用 XML、PHP 和 Adobe 的可缩放向量图形(SVG)标准创建商业图像。SVG 标准为图像提供了无限级的向量缩放、可视化效果以及基于脚本的交互性。

Jack D Herrington (jherr@pobox.com), 高级软件工程师, Leverage Software Inc.

Jack D. Herrington 是一位具有 20 多年经验的资深软件工程师。他撰写了三本书:Code Generation in ActionPodcasting Hacks PHP Hacks,此外还有 30 多篇文章。可以通过 jherr@pobox.com 与 Jack 联系。



2006 年 10 月 16 日

我承认,我是一个图像痴迷者。从孩提时候起我就喜欢有漂亮图像的计算机。这也是与 TRS-80 相比我更喜欢 Apple II 计算机的原因。不过有谁不喜欢图片呢?谁不曾被 Pixar 电影征服?“一张图片胜过千言万语” 这句老话没有错,因为一幅图片能够又快又容易地传达大量信息。

图像对于商业数据的重要性其他任何地方都比不上。通过 SVG 之类的标准来充分利用图像代码非常重要,因为众所周知,Web 上早就不缺乏图像了。当然可以把图片放在网页中,但通常这些图片的作用不大。这些照片不能缩放和滚动,不能交互,不能很好地打印和调整比例。不过,我相信 Web 2.0 将改变这种局面。不再需要强调这种技术的重要性。本文的目的是给用户以包括图像的体验。打开 Google 的 Finance 页面,如 图 1 所示。查看股票的时候,可以使用交互式图像控件滚动数据,找到感兴趣的地方。是否使用 Macromedia Flash 实现有关系吗?没有。重要的是最终结果 —— 客户体验。

图 1. Google Finance 页面
Google Finance 页面

本文将通过例子说明如何使用 Adobe SVG 格式和 PHP 编程语言创建漂亮的交互式图形。首先,了解一下 SVG 的背景知识及其与 Web 图像技术的关系。

可缩放向量图形

Adobe 的 SVG 标准是一种基于 XML 的表示向量图形的格式。基础是直线、矩形、形状、图片和文本这些元素。所有这些元素都在 “视图坐标” 中指定,坐标值不是像素,只是适合应用程序的需要而定义的任意数值范围。这样就可以将 XML 指定的图像模型呈现到任意的图像空间中 —— 无论多么大或者多么小 —— 并进行适当的缩放。向量图像可以用打印机的最大分辨率打印,不会出现位图放大打印时常见的锯齿。

这种格式还允许对任何对象或对象组应用特效。其中包括投影、斜角、纹理、外测发光、内测发光等等。如果熟悉 Adobe PhotoShop 或 Elements,就会知道这些效果。还可以使用旋转、倾斜、透明、剪裁等技术。

不仅如此,SVG 的标记还可用于动态改变这些属性,因此可以沿着路径移动图形对象或者实现淡入淡出效果。此外,SVG 还允许在模型中添加 JavaScript 代码,为图形元素、效果和动画加上行为。

我第一次看到 SVG 的时候,立刻被它吸引并钻了进去。照我看来,Adobe 是把 PhotoShop 引擎变成了能够嵌入到网页中的控件。事实上,今天看来仍然如此。不足之处是,我发现并非所有的客户机上都安装了 SVG,而且安装它需要下载某些软件。我不可能这样要求客户。因此有段时间我把 SVG 放在了一边,直到最近发现 SVG 的一个子集安装到了 Mozilla Firefox V1.5 中。现在,我想对于 SVG 来说事情将向好的方面转化。

但是我们再后退一步,将 SVG 置于 Web 图像的大背景中。


SVG 和它所属的世界

几年以前,如果想为 Web 创建图像,选择很有限。您可以即时创建 PHP 图片和建立 .jpeg、.gif 或 .png 文件。但是这些图像往往很简陋,因为 PHP 图像库非常原始,不支持特效。此外图像的缩放也不够好。

技术有了一点进步,现在有更多的选择了。当然,其中包括 SVG。但是还有 Flash。Flash 可以使用画布对象和 JavaScript 代码绘制任何图像。还能够从服务器上直接以 XML 或 JavaScript Serialized Object Notation (JSON) 的形式把数据读入到图像中。

在 Flash 之上有两种相对较新的技术。第一个是 Adobe Flex,这种基于 XML 标记的语言可以呈现为 Flash,并且包含图形库。Flex 的竞争对手之一是 Laszlo。Laszlo 也使用标记,优点是开放源代码。

还可以在浏览器中使用 <canvas> 标记。这种新标记是一个画布,可以在其上绘制直线和矩形、放置图片、进行旋转等。听起来似乎不错,但 Microsoft® Internet Explorer 不支持它 —— 目前来说。幸运的是,Google 有一个开放源代码项目 InternetCanvas,在 Internet Explorer 中提供了相同的能力。

刚出现的另一种选择是 Microsoft Windows Presentation Foundation (WPF),它提供的 XML 标记可以创建能够嵌入浏览器的 Windows User Interfaces。是不是只能用于 Microsoft Windows® 呢?的确。但是还有 WPF/E,它为 Mac 和 Windows 上的所有主流浏览器提供了 WPF 的一个功能子集。

确实有不少选择。不过本文选择 SVG,并结合使用 PHP 为股票数据绘制一些图像。


SVG 的 Hello World

为了确保您的 Firefox V1.5 浏览器能够正确处理 SVG 或者有一个安装了 SVG 插件的浏览器,我提供了一个简单的类似 “Hello World” 的例子供您测试。首先,我创建了一个文件 start.html,如 清单 1 所示。作为引用 .svg 文件的网页。

清单 1. Start.html
<html>
<body>
<embed src="start.svg" height="300" width="300" type="image/svg+xml"
 pluginspage="http://www.adobe.com/svg/viewer/install/" 
 style="border: 1px solid black; padding:5px;"/>
</body>
</html>

然后需要一个 start.svg 文件,如 清单 2 所示。可以看到 .html 文件中 <embed> 标记引用了该 .svg 文件。

清单 2. Start.svg
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd">
<svg style="shape-rendering:geometricPrecision;"
  viewBox="0 0 100 100" xml:space="preserve"  
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns="http://www.w3.org/2000/svg"
  preserveAspectRatio="xMidYMid meet">
   <path fill-rule="nonzero"
     style="fill:#000000;stroke:#FF0000;"
     d="M0 0 L100 100 Z"/>
   <path fill-rule="nonzero"
     style="fill:#000000;stroke:#00FF00;"
     d="M50 0 L50 100 Z"/>
   <path fill-rule="nonzero"
     style="fill:#000000;stroke:#FF0000;"
     d="M0 100 L100 0 Z"/>
   <path fill-rule="nonzero"
     style="fill:#000000;stroke:#00FF00;"
     d="M0 50 L100 50 Z"/>
</svg>

在浏览器中打开该文件时,可以看到 图 2 所示的结果。

图 2. .svg 测试文件
.svg 测试文件

回头再看看那个文件,其中定义了四条路径:两条从角到角,另外两条绿色的沿中心从上到下。如果看到该图像,说明您的浏览器至少能呈现 SVG 的一个小子集。


获取数据

绘图从数据开始。这里我使用两家公司 31 天的股票数据。包含股票数据的 XML 文档的一部分如 清单 3 所示。

清单 3. data.xml 片段
<stocks>
<stock>
<day high="35.13" low="32" close="33.75" />
<day high="32.25" low="28.75" close="31.75" />
<day high="29" low="28.5" close="28.87" />
<day high="29.25" low="28.75" close="28.75" />
<day high="29.5" low="28.5" close="29.25" />
<day high="30.25" low="29" close="29.25" />
...
</stock>
</stocks>

格式很简单。根标记 <stocks> 包含一组 <stock> 标记。每个 <stock> 标记包含一些 day 标记,带有 highlowclose 属性。

接下来要编写将该文件读入内存以便用于生成 SVG 的代码。这里我用了三个 PHP 类,如 清单 4 所示。

清单 4. Data.php
<?php
class Day
{
  var $low;
  var $high;
  var $close;

  public function __construct( $low, $high, $close )
  {
    $this->low = $low;
    $this->high = $high;
    $this->close = $close;
  }
}

class Trace
{
  var $days = array();
  var $high = 0.0;
  var $low = 100000.0;

  public function addDay( $low, $high, $close )
  {
    $this->days []= new Day( $low, $high, $close );
    if ( $low < $this->low ) $this->low = $low;
    if ( $high > $this->high ) $this->high = $high;
  }

  public function hiloPath( $trans )
  {
    $p = new Path();
    $d = 0;
    foreach( $this->days as $day )
    {
      $x = $trans->xscale( $d );
      $y = $trans->yscale( $day->low );
      $p->add( $x, $y );
      $d += 1;
    }
    for( $d = (count( $this->days ) - 1); $d >= 0; $d -= 1 )
    {
      $x = $trans->xscale( $d );
      $y = $trans->yscale( $this->days[$d]->high );
      $p->add( $x, $y );
    }
    return $p;
  }

  public function closePath( $trans )
  {
    $p = new Path();
    $d = 0;
    foreach( $this->days as $day )
    {
      $x = $trans->xscale( $d );
      $y = $trans->yscale( $day->close );
      $p->add( $x, $y );
      $d += 1;
    }
    return $p;
  }
}

class Data
{
  var $traces = array();
  var $high = 0;
  var $low = 100000;

  function parseXML( $file )
  {
    $data_dom = new DomDocument();
    $data_dom->load( $file );

    $elStocks = $data_dom->getElementsByTagName( 'stock' );
    foreach( $elStocks as $stock )
    {
      $trace = new Trace();

      $days = $stock->getElementsByTagName( 'day' );
      foreach( $days as $day )
      {
        $trace->addDay( (float)$day->getAttribute('low'),
          (float)$day->getAttribute('high'),
          (float)$day->getAttribute('close') );
      }
    
      $this->traces []= $trace;

      if ( $trace->high > $this->high ) $this->high = $trace->high;
      if ( $trace->low < $this->low ) $this->low = $trace->low;
    }
  }
}
?>

Data 类包含文件中的所有数据。每支股票存储在一个 Trace 对象中。每 Trace 对象包含一组 Day 对象,定义了当天的最高价、最低价和收盘价。此外,Trace 对象知道如何为图像中的最高、最低和收盘价部分创建 Path 对象。

Path 对象是一个 PHP 类,是我自己为了方便创建 SVG 路径专门编写的。这个帮助器类在 svg.php 文件中定义,如 清单 5 所示。

清单 5. Svg.php
<?php
interface ITransform
{
  function xscale( $x );
  function yscale( $x );
}

class Transform implements ITransform
{
  protected $ox;
  protected $oy;
  protected $xscale;
  protected $yscale;
  protected $xoffset = 0;
  protected $yoffset = 0;

  public function xscale( $x ) {
    return $this->ox + ( ( $x - $this->xoffset ) * $this->xscale );
  }

  public function yscale( $y ) {
    return $this->oy - ( ( $y - $this->yoffset ) * $this->yscale );
  }
}

class Point
{
  var $x;
  var $y;
  public function __construct( $x, $y )
  {
    $this->x = $x;
    $this->y = $y;
  }
}

class Path
{
  private $points = array();

  public function add( $x, $y )
  {
    $this->points []= new Point( $x, $y );
  }

  public function toSVG()
  {
    $svg = "";
    $svg .= "M ".$this->points[0]->x." ".$this->points[0]->y." ";
    foreach( $this->points as $pt ) {
      $svg .= "L ".$pt->x." ".$pt->y." ";
    }
    return $svg;
  }
}
?>

这里定义了两个类,都很容易理解:PointPathPoint 类表示一个 X-Y 值对,Path 类是一组 PointsITransform 接口和 Transform 基类更有意思。为了绘制股票图像,必须将美元和每日数据的尺度转化成 SVG 视图坐标。ITransform 接口就是为了完成这项任务而定义的,但是不仅仅完成该任务。


绘制图像

我将分阶段逐步完成整个图像。

版本 1:绘制收盘价路径

第一个版本中仅仅绘制收盘价路径,这样可以看出 data.xml 文件中的两支股票在 31 天中的走势。清单 6 显示了第一个版本的代码。

清单 6. graph.php 的第一个版本
<?php
require_once( 'svg.php' );
require_once( 'data.php' );

class GraphTransform extends Transform
{
  public function __construct( $ox, $oy, $width,
    $height, $low, $high, $days )
  {
    $this->ox = $ox;
    $this->oy = $oy;
    $this->xscale = $width / ( $days - 1 );
    $this->yscale = $height / ( $high - $low );
    $this->yoffset = $low;
  }
}

$d = new Data();
$d->parseXML( 'data.xml' );

$ystart = (int)$d->low - 2;
$yend = (int)$d->high + 2;

$gt = new GraphTransform( 20, 90, 80, 80,
  $ystart, $yend, count( $d->traces[0]->days ) );

header( "Content-type: text/xml" );
echo( "<?xml version=\"1.0\" standalone=\"no\"?>\n" );
?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd">
<svg style="shape-rendering:geometricPrecision;"
  viewBox="0 0 100 100" xml:space="preserve" 
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns="http://www.w3.org/2000/svg"
  preserveAspectRatio="xMidYMid meet">

<style type="text/css">
.close { fill-opacity: 0; stroke-opacity:0.8;
 stroke-width: 0.4; }
</style>

<?php
foreach( $d->traces as $trace )
{
  $closePath = $trace->closePath( $gt );
  $closeSVG = $closePath->toSVG();
  $color = "#ff0000";
?>
   <path fill-rule="nonzero"
   d="<?php echo( $closeSVG ); ?>" class="close"
   fill="<?php echo( $color ); ?>"
   stroke="<?php echo( $color ); ?>"
   />
<?php
}
?>
</svg>

文件的一开始创建了 ITransform 接口的一个版本,它把美元值沿着 Y 轴、当日价格沿着 X 轴转化成 SVG 的点。然后在文件的后面,使用 foreach 迭代器遍历数据中的轨迹列表。对于每个轨迹,使用 SVG Path ($closeSVG) 获得收盘价,并将该值使用 toSVG() 方法转化成 SVG 绘图命令。然后创建一个 SVG <path> 标记,并使用 PHP echo 命令写入绘图命令以及 fill 和 color 值。

浏览引用该图像的 .html 文件时得到了如 图 3 所示的结果。

图 3. 第一个版本
第一个版本

看起来不怎么样,但它是正确的,这仅仅是开始。

版本 2:撑起收盘线

下一步要用稍微亮一点的图形撑起收盘线,它表示当日的最高价和最低价。这样可以让客户了解股票价格的变化。

为此修改了 PHP 绘图文件,如 清单 7 所示。

清单 7. graph.php 的第二个版本
<style type="text/css">
.close { fill-opacity: 0; stroke-opacity:0.8; stroke-width: 0.4; }
.hilo { fill-opacity: 0.2; stroke-opacity:0.8; stroke-width: 0.1; }
</style>

<?php
$colors = array( '#ff0000','#0000ff','#00ff00' );
$c = 0;
foreach( $d->traces as $trace )
{
  $closePath = $trace->closePath( $gt );
  $closeSVG = $closePath->toSVG();
  $hiloPath = $trace->hiloPath( $gt );
  $hiloSVG = $hiloPath->toSVG();
  $color = $colors[$c];
  $c += 1;
?>
   <path fill-rule="nonzero"
   d="<?php echo( $hiloSVG ); ?>" class="hilo"
   fill="<?php echo( $color ); ?>"
   stroke="<?php echo( $color ); ?>"
   />
   <path fill-rule="nonzero"
   d="<?php echo( $closeSVG ); ?>" class="close"
   fill="<?php echo( $color ); ?>"
   stroke="<?php echo( $color ); ?>"
   />
<?php
}
?>

与原来的收盘线基本类似,只不过使用了 hiloPath。然后我使用 close 类创建了另一条路径。要注意 SVG 如何运用了将级联样式表(CSS)类应用于不同图形对象的思想。可以在类级别或者实例级别设置笔触、透明度、填充以及其他任何图形样式,如果需要甚至可以使用脚本随时改变。

图 4 显示了修改后的版本。

图 4. 显示了最低价和最高价的图像
显示了最低价和最高价的图像

现在可以看到股价的变动了。如果仔细观察图像的开始部分,会看到最低价和最高价图形的交叠,就是说透过红色的踪迹仍然能看到蓝色的踪迹。

版本 3:添加边框和文本

下一个版本中增加了边框和表明美元价格的文本。变化如 清单 8 所示。

清单 8. graph.php 的第三个版本
<style type="text/css">
.close { fill-opacity: 0; stroke-opacity:0.8; stroke-width: 0.4; }
.hilo { fill-opacity: 0.2; stroke-opacity:0.8; stroke-width: 0.1; }
.range { text-anchor: end; font-size: 5pt; }
</style>
...
  <line x1="18" y1="10" x2="20" y2="10"
   stroke="black" stroke-width="0.2" />
  <line x1="20" y1="10" x2="20" y2="92"
   stroke="black" stroke-width="0.2" />
  <line x1="18" y1="90" x2="100" y2="90"
   stroke="black" stroke-width="0.2" />
  <line x1="100" y1="90" x2="100" y2="92"
   stroke="black" stroke-width="0.2" />
  <text x="18" y="12" class="range"><?php echo($yend); ?>
  </text>
  <text x="18" y="92" class="range"><?php echo($ystart); ?>
  </text>
</svg>

呈现图像的 PHP 代码没有变。仅仅在 Y 轴上画了几条线和一些文本。修改后的版本如 图 5 所示。

图 5. 带有边框和 Y 轴坐标值的图像
带有边框和 Y 轴坐标值的图像

版本 4:添加背景

最后一步在数据后面增加了一点渐变填充的背景色来突出数据。清单 9 表明添加这种填充效果是多么简单。

清单 9. 渐进填充
<svg style="shape-rendering:geometricPrecision;"
  viewBox="0 0 100 100" xml:space="preserve" 
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns="http://www.w3.org/2000/svg"
  preserveAspectRatio="xMidYMid meet">

<defs>
<linearGradient id="BackGradient"
 gradientUnits="objectBoundingBox"
 gradientTransform="rotate(90)">
  <stop offset="0%" stop-color="#ccc"/>
  <stop offset="50%" stop-color="white"/>
  <stop offset="100%" stop-color="#ccc"/>
</linearGradient>
</defs> 

<style type="text/css">
.close { fill-opacity: 0; stroke-opacity:0.8; stroke-width: 0.4; }
.hilo { fill-opacity: 0.2; stroke-opacity:0.8; stroke-width: 0.1; }
.range { text-anchor: end; font-size: 5pt; }
.background { stroke-width: 0; fill:url(#BackGradient); }
</style>

  <rect x="20" y="10" width="80" height="80" class="background" />
...

代码中的新类 background 使用了 BackGradientlinearGradient 填充在浅灰到白色之间有三站,然后再过渡到浅灰。结果如 图 6 所示。

图 6. 最终的图像
最终的图像

现在举例说明 SVG 中的缩放,我稍微修改了页面,增加了 <embed> 标记的宽和高。结果如 图 7 所示。

图 7. 图像的缩放
图像的缩放

各处都得到了完美的放大,没有任何锯齿。是不是棒极了?……我告诉您,太棒了。我特别喜欢 SVG 对单位的处理,它非常适合程序员,无需直接使用像素。


制作 SVG 的其他方法

显然,PHP 不是创建 .svg 文件的惟一手段。任何编程语言 —— C#C、Java™ 语言、Perl —— 都能创建 SVG 文本文件。Perl 的 Comprehensive Perl Archive Network (CPAN) 库中有一个 SVG 模块。PHP 有支持 SVG 的 PEAR 模块,使用 Java 的人可以考虑 Apache Foundation 的 Batik SVG Toolkit。

另一种替代语言是可扩展样式表语言转换(XSLT),很容易将 XML 数据文件转换成 .svg 文件。ChartSVG 是一个开放源代码的绘图项目,使用以 XSLT 编写的 SVG。

作为前端工具,Adobe Illustrator 和 GoLive 可以创建 .svg 文件。GNU Image Manipulation Program (GIMP) 也支持从路径导出 SVG。我最喜欢的绘图程序 OmniGraffle V4.0 也支持导出 SVG。至于科学应用程序,Mathematica 有一个导出 SVG 的扩展。


结束语

Firefox V1.5 中增加的 SVG,即便非常基本,仍然为 Web 设计者打开了一个新的世界。Firefox 的确不如 Internet Explorer 普及,但是它拥有不断增长的技术社区所特有的共享情结。共享为其他制造商提供了强大的动力,在其浏览器中包含更好的 SVG 支持,打开了为客户创造更丰富的图像体验的大门。


下载

描述名字大小
Contains start.html and start.svgx-graphxmlsvg/start.zip1KB
The data.xml filex-graphxmlsvg/data.zip1KB
The graph.php filex-graphxmlsvg/graph.zip2KB

参考资料

学习

  • 您可以参阅本文在 developerWorks 全球网站上的 英文原文
  • PHP 主页:PHP 主页包含大量关于这种脚本语言的资料。
  • W3C XML 页面:万维网联盟(W3C))XML 页面是进一步学习 XML 和相关标准的好去处。
  • SVG 标准:W3C 也接纳了 SVG 标准。
  • Adobe 的 SVG 网站:SVG 的优秀资源站点,提供了丰富的信息。
  • Mozilla SVG Project:Mozilla SVG Project 解释了 Firefox 支持什么不支持什么。
  • SVG.org:该 SVG 主页包括关于 SVG 的新闻和信息。
  • SVG Essentials:David Eisenberg (O'Reilly, 2002) 撰写的 SVG Essentials 详细介绍了 SVG。
  • 在 SVG 中添加交互性(developerWorks,2003 年 8 月):为 SVG 文档增加能够响应用户输入的交互元素。
  • XML 问题: 使用 SVG 编程(developerWorks,2005 年4 月):了解 SVG 脚本和动画、如何通过 DOM 和其他常见 XML 工具以及库来操作 SVG。
  • 交互式动态可伸缩向量图形(developerWorks,2003 年 6 月):使用 XSLT 和其他技术从 XML 数据动态创建 SVG 图像,比如支持 XML 的关系数据库管理系统。该教程中的例子使用 JavaScript,让用户能够动态控制用 SVG 呈现的建筑平面图的内容和形式。
  • SVG-可伸缩向量图形介绍(developerWorks,2004 年 3 月):了解如何从数据库信息生成图像(如图形和图表),包括动画和交互性。该教程示范了创建 SVG 文档需要了解的概念,包括基本形状、路径、文本和绘图模型以及动画和脚本。
  • IBM XML 1.1 认证:了解如何才能成为一名 IBM 认证的 XML 1.1 及相关技术的开发人员。
  • XML:developerWorks 中国网站 XML 专区提供了各种技术文章和技巧、教程、标准和 IBM 红皮书。

获得产品和技术

  • WPF 和 XAML:WPF 和可扩展应用程序标记语言(XAML)是 Microsoft 对 SVG 的回应。
  • SVG CPAN 模块:该手册非常适合 Perl 程序员。
  • Batik:Apache XML Project 的 Batik 是一种用于 Java 语言的 SVG 工具箱。
  • ChartSVG:Hardcoded Software 的 ChartSVG 是一种用于创建 SVG 图像的 XSLT 转换系统。
  • OmniGraffle:Omni Group 的 OmniGraffle 是一种用于商业和技术设计的 Macintosh 应用程序。
  • Mathematica:Wolfram Research 的 Mathematica 是一种科学工具箱,能够导出 SVG。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML, Open source, Web development
ArticleID=168631
ArticleTitle=SVG 与 XML 商业图表实务
publish-date=10162006