65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 JavaScript 的桥接设计模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (17投票s)

2006 年 9 月 22 日

CPOL

11分钟阅读

viewsIcon

78920

downloadIcon

570

本文档解释了桥接设计模式是什么,并介绍了一个极简的跨浏览器矢量图形(SVG + VML)库,该库使用 JavaScript 编写,并在该模式的帮助下构建。

前言

感谢您花时间阅读本文。如果您想投个票(特别是低分的话),请务必附带评论说明问题所在。我的文章获得的票数大部分都很高,除了偶尔的 1 或 2 分,我真的很想知道是什么最困扰那些投票者。反馈是改进的动力。

本文假设您熟悉 JavaScript 语言的面向对象方面。如果不是,建议您阅读 Salvatore Vetro 的文章的前半部分。

本文结构如下

问题

图形内容是每个 Web 开发人员在创建的每个页面中都会处理的事情。当它不仅仅是放置一个 `<IMG>` 标签时,问题就开始了。您可能希望构建一个基于 Web 的图形编辑器、游戏、广告横幅、交互式预览器等。

首先想到的解决方案是 Flash。您几乎可以用它满足任何 Web 图形需求,但缺点可能令人望而却步。它们是:需要投入文档、工具和程序员的资金;对浏览器内脚本支持不足;与众多 Web 媒体标准不兼容;Flash Player 安全问题;等等。

基于 XML 的标准是替代方案。它们提供完美的 Web 集成(如 XML 所提供的),可扩展,并且不需要下载大型二进制文件。唯一的缺点是 XML 仍然是一项新兴技术,因此在处理 XML 语法时会遇到许多不兼容问题。

为了开始 Web 图形,我们需要一些简单的,就像这样

<script type="text/javascript">

  var vgr = new VectorGraphics(...);

  vgr.MoveTo(100, 100);
  vgr.Rect(100, 100, "#0F0");

  vgr.MoveTo(350, 350);
  vgr.Circle(50, "#F0F");

  ...

</script>

一如既往,完成一项工作的方法不止一种。确切地说,方法数量等于 Web 上的浏览器、插件和标准(相互交叉相乘……)的数量。为了满足所有客户(或至少是大多数客户)的需求,您必须走遍所有这些道路……您是否想再次面对那些多页面的浏览器和平台检测的东西(以及所有那些容易迷失的开关和 `if`)?我不愿意。

因此,在继续讨论矩形和圆形之前,我们需要回答两个并非那么简单的问题

  • 我们如何构建一个对象库,它能在有多种选择的情况下,取其精华(两到三到四种……)?
  • 我们如何构建一个易于扩展和维护的对象库?

答案是

桥接模式

注意: JavaScript 是一种基于原型的语言,不支持许多面向对象语言共有的特性。在有意义的地方,我会添加注释描述差异和旁白;它们被标记为 [JavaScript]。

  • 动机

    考虑实现一个跨浏览器的矢量图形库。它的主要目的是允许我们将 (X)HTML 页面用作绘图画布,以便我们可以绘制各种形状:线条、矩形、圆形等。它还应该使我们能够编写在支持 SVGVML 标准的任何浏览器上运行的脚本。使用继承([JavaScript]:原型链),我们可以定义一个 `VectorGraphics` 接口,以及实现该接口的 `VectorGraphicsImplSVG` 和 `VectorGraphicsImplVML` 类。

    这种方法有两个问题

    1. 要将 `VectorGraphics` 抽象扩展到覆盖更专业的矢量图形 API 或新平台非常不方便。想象一下 `VectorGraphics` 的 `GeoGraphics` 子类,它将矢量图形专业化用于显示 GIS 数据。为了同时支持 SVG 和 VML 用户代理的 `GeoGraphics`,我们必须实现两个新类,`GeoGraphicsImplSVG` 和 `GeoGraphicsImplVML`。更糟糕的是,每一种新的基于 XML 的图形标准,我们都需要定义两个类。支持第三种 API 需要为 `VectorGraphics` 的每种特定情况再添加一个新的矢量图形子类。每个框架扩展都会导致类/原型层次结构的爆炸式增长。

    2. 一旦支持的程序员拥有了 `GeoGraphicsImplSVG` 和 `GeoGraphicsImplVML`,他/她应该实例化哪个类?很明显,`VectorGraphics` 类本身必须“决定”向最终用户展示哪个类。换句话说,客户端应该能够实例化一个 `VectorGraphics` 对象而无需绑定到具体的实现。只有实现类应该依赖于脚本运行的平台。因此,客户端代码应该实例化 `VectorGraphics` 而不提及特定的图形标准。

    桥接模式通过将 `VectorGraphics` 抽象及其所有实现放在单独的类/原型层次结构中来解决此问题。有一个用于 `VectorGraphics` 接口的层次结构(`VectorGraphics`、`GeoGraphics`、`UIGraphics`),以及一个用于平台特定实现的独立层次结构,以 `VectorGraphicsImpl` 为根(详见下文)。例如,`VectorGraphicsImplSVG` 提供基于 SVG 渲染子系统的实现。

    VectorGraphics 和 `VectorGraphicsImpl` 之间的这种关系称为**桥接**,因为它连接了接口及其实现,使它们能够独立变化。

    (C++ 大师可以说:“桥接模式增加了一个‘间接层’,就像**代理**模式一样”。)

  • 适用性

    在以下情况下使用桥接模式

    • 您希望显式地分离自定义对象的接口和实现。这允许您在运行时选择(甚至切换)实现者。
    • 抽象及其实现都应该是可扩展的(通过子类化或原型链)。这可以防止类层次结构的失控增长,并允许您避免累积编码错误(对实现类所做的更改不会影响接口类)。这就是为什么桥接模式非常适合用作跨平台框架的基础。
    • 您希望本地化平台特定的代码,从而使您的脚本易于扩展和维护。
    • 您希望本地化浏览器/功能/对象检测代码。(注意:您可能希望或不希望这样做;桥接模式的结构会迫使您这样做。)

  • 结构

  • 参与者

    • 抽象

      • 定义抽象的接口
      • 维护对实现者对象的引用
    • 精化抽象

      • 扩展由抽象定义的接口
    • 实现者

      • 定义实现类的接口。此接口可能与抽象接口相同,也可能不同。

      注意:由于 JavaScript 是一种松散类型的语言,没有抽象类的概念,因此 `Implementor` 在桥接模式的 JavaScript 实现中并不常见。通常会有一组 `ConcreteImplementors`;您可以在设置桥接时将 `abstraction` 的实现者引用设置为 `ConcreteImplementors` 之一。所有 `ConcreteImplementors` 都必须符合选定的接口,就好像所有具体的实现者都是 `Implementor` 的子类一样。

    • 具体实现者
      • 实现 `Implementor` 接口并定义其具体实现。

  • 协作

    抽象将客户端请求转发给其 `Implementor` 对象。

  • 示例实现

    注意:这不是一个示例脚本;请将其视为一个用于剪切并粘贴到您的脚本文件并开始编码的填充表。

    // Abstraction - the object you usually create
    //               in your "end-user" scripts:
    //
    // <SCRIPT type="text/javascript">
    
    //
    //    var abstr = new Abstraction();
    //    ...
    //
    // </SCRIPT>
    //
    function Abstraction()
    {
    // Implementation reference:
    
      this._impl = null;
    
    // Setup procedure:
    
      this._SetImplementation(this._EstablishImplementor(container));
    
      return this;
    }
    
    Abstraction.prototype = {
    
      _SetImplementation: function(implementor)
      {
        this._impl = null;
        if(implementor) this._impl = implementor;
      },
    
      // EstablishImplementor - function that creates
      // the Concrete Implementor and binds it to Abstraction.
      // This is the very method to place your
      // browser/feature/object detection code.
      _EstablishImplementor: function()
      {
        if(/*conditionOne*/)
          return new ImplementationOne();
    
        else if(/*conditionTwo*/)
          return new ImplementationTwo();
    
        // ...
    
        return null;
      },
    
      // Function "exported" by the Abstraction:
      FuncOne: function()
      {
        // Check if any implementor is bound and has the required method:
        if(_impl && _impl.FuncOne)
           _impl.FuncOne();     // Forward request to implementor
      }
    };
    
    // ...
    
    // This is the first in the set of concrete implementors:
    function ImplementationOne()
    {
    // ...
    }
    
    ImplementationOne.prototype = {
    
      // This "public" function is directly called by Abstraction:
      FuncOne: function()
      {
        // ...
      },
    
    // ...
    }
    
    // This is the second implementor:
    function ImplementationTwo()
    {
    // ...
    }
    
    ImplementationTwo.prototype = {
    
      FuncOne: function()
      {
        // ...
      },
    
    // ...
    }

    注意 1:示例中的 `_EstablishImplementor` 是`工厂方法`模式的一个示例。我们使用它来本地化要实例化的辅助类的知识。

    注意 2:为了完成模式的讨论,我必须说 JavaScript 语言本身就是建立在 `原型` 模式之上的。每个对象都派生自一个原型(原型实例);对象创建实际上是克隆原型的操作。

案例研究:SVG vs. VML

注意: SVG/VML 的情况(简而言之)前面已经解释过;本节将深入回顾问题并提出解决方案。

  • 概述

    有两种知名的 Web 图形标准:SVG 和 VML。两者都提供

    • 用于描述二维图形的基于 XML 的语言
    • 语言中立的编程 API(**D**ocument **O**bject **M**odel)
    • 与其他 XML 语法无缝集成(通过 XML 命名空间)。

    区别

    • SVGScalable **V**ector **G**raphics)- 由 W3C 支持,这是真正的行业级举措,旨在将矢量图形带到 Web。

      • 极其庞大的规范,涵盖了 Web 图形的每一个方面:形状、文本、滤镜、动画、音频/视频、交互性、脚本等。
      • 模块化标准
      • 完整规范可用
      • 有各种实现可用

      问题是

      • 内联 SVG 与 HTML 4 不兼容;所有参考都建议处理 XHTML 文档。
      • 浏览器支持仍然很差,即使考虑到 Mozilla (Firefox)Opera 和可用的插件。当前的开发速度表明这种情况是暂时的。

      可通过以下方式获得

      • Mozilla Firefox 浏览器 - 从 1.5 版开始提供原生支持(截至 2006 年 9 月,SVG 支持不完整);
      • Opera 浏览器 - 从 9 版开始提供原生支持(捆绑插件)(截至 2006 年 9 月,SVG 支持不完整且有些错误);
      • MS Internet Explorer - 通过 Adobe SVG Viewer
      • 任何支持 Java 技术的浏览器 - 通过 Batik applet。

    • VMLVector **M**arkup **L**anguage)- 另一个(说实话,也是最早的,可追溯到 1998 年)倡议,仅由 Microsoft 支持。

      • 功能受限(与 SVG 相比)
      • 文档松散
      • 不受 WWW 社区支持(也可能永远不会)。潜在的过时技术。

      但是

      • 自 5.5 版起被 Microsoft Internet Explorer 原生支持 - 最大的安装查看器基数。
      • 可以集成到任何 HTML 文档中(作为 XML 岛)。
      • 与 Microsoft Office 产品系列紧密集成。

      可通过以下方式获得

      • Microsoft Internet Explorer - 从 5.5 版开始。

      注意:在比较 SVG 和 VML 规范的贡献者列表时,您可能会注意到这些列表是重叠的。这可能表明 Microsoft 很可能已经放弃了 VML 开发而转向 SVG。尽管如此,VML 仍然值得一看,因为即使是最新版本的 Microsoft IE(截至 2007 年 7 月的第 7 版)也保留了对其的原生支持(并且不原生支持 SVG)。

    对于不支持这两种标准的浏览器,存在一种替代方案:Walter Zorn 的高性能 JavaScript 图形库。它使用 `DIV` 来绘制形状,因此不依赖于任何标准。

  • 库接口

    这是一个 `VectorGraphics` 对象的、高层 API。不太广泛,但足以满足最常见的绘图需求。

    下面列出的所有函数都是“`public`”,即供客户端使用,而不是“`private`”函数(带有前导下划线),由库内部使用。

    // VectorGraphics - the object you should create in your "end-user"
    // scripts.
    // 'Container' parameter defines an empty DIV or SPAN, which will serve
    //           as a painting canvas.
    //
    // <SCRIPT type="text/javascript">
    //
    //    var vg = new VectorGraphics(document.getElementById("container"));
    //    ...
    //
    // </SCRIPT>
    
    function VectorGraphics(container)
    { ... }
    
    VectorGraphics.prototype = {
    
      // MoveTo(x, y) - moves current painting position to a point
      //                with the coordinates of (x, y).
      MoveTo: function(x, y)
      { ... },
    
      // LineTo(x, y) - draws a line from current position
      //               (defined by a previous MoveTo call)
      //                to a point with the coordinates of (x, y).
      //                Line is drawn with current stroke color,
      //                line width is equal to current stroke width.
      LineTo: function(x, y)
      { ... },
    
      // Rect(x, y, width, height) - draws a rectangle. Upper-left
      //                corner is defined by the current position
      //               (probably set by a previous MoveTo call);
      //                lower-right corner is:
      //
      //                (currentX + width, currentY + height).
      //
      //                Rectangle is filled with current fill color,
      //                border is drawn with current stroke color,
      //                border width is equal to current stroke width.
      Rect: function(width, height)
      { ... },
    
      // Ellipse(rx, ry) - draws an ellipse; center
      //                is defined by the current position
      //               (probably set by a previous MoveTo call);
      //                radii are rx and ry. Ellipse is filled with
      //                current fill color, border is drawn with
      //                current stroke color, border width is equal
      //                to current stroke width.
      Ellipse: function(rx, ry)
      { ... },
    
      // Polygon(arrayofPoints) - draws a polygon. arrayofPoints
      //                has the following format:
      //
      //                [[x1, y1],[x2, y2], ... [xn, yn]]
      //
      //                Unlike all other functions, previous MoveTo call
      //                doesn't define the starting point. Polygon is
      //                filled with current fill color, border is drawn
      //                with current stroke color, border width is equal
      //                to current stroke width.
      Polygon: function(arrayofPoints)
      { ... },
    
      // Text(string) - draws a string at the current position
      //               (probably set by a previous MoveTo call);
      //                Text is drawn with the current font color,
      //                and at a current font size.
      Text: function(string)
      { ... },
    
      // SetFillColor(rgb) - sets the fill color,
      //                     in #xxx or #xxxxxx format.
      SetFillColor: function(rgb)
      { ... },
    
      // SetStrokeColor(rgb) - sets the stroke (line) color,
      //                     in #xxx or #xxxxxx format.
      SetStrokeColor: function(rgb)
      { ... },
    
      // SetStrokeWidth(rgb) - sets the stroke (line) width.
      SetStrokeWidth: function(rgb)
      { ... },
    
      // SetFont(fontNames, fontSize, fontColor, fontVariant) - sets
      //             the font family (fontNames), font color (fontColor),
      //             and font variant (fontVariant, not currently used).
      SetFont: function(fontNames, fontSize, fontColor, fontVariant)
      { ... }
    }
  • 具体实现

    `VectorGraphics` 配备了两个实现者:`VectorGraphicsImplSVG` 和 `VectorGraphicsImplVML`。实现者在运行时由 `VectorGraphics.prototype._EstablishImplementor` 方法选择,这是本地化浏览器检测代码的地方。该函数仅创建并返回支持的实现者。

    // Checks for MSIE + Adobe SVG plugin installation:
    VectorGraphics.prototype = {
    
      _CheckASV: function()
      {
        var adobeplugin = false;
    
        if((navigator.userAgent.toLowerCase().indexOf("msie") != -1) &&
                                                     (!window.opera))
        {
          var obj = null;
          try
          {
            obj = new ActiveXObject("Adobe.SVGCtl");
            if(obj)
            {
              adobeplugin = true;
              obj = null;
            }
          }
          catch(e) {};
        }
    
        return adobeplugin;
      },
    
      _EstablishImplementor: function(container)
      {
        if((navigator.mimeTypes &&
                (navigator.mimeTypes["image/svg+xml"] ... ))
           ||
           // Firefox 1.5+ supports SVG natively:
           (navigator.userAgent.toLowerCase().indexOf("firefox")
                                      != -1) && !window.opera)
          return new VectorGraphicsImplSVG(container);
    
        else if(this._CheckASV())
          // MSIE + Adobe SVG plugin:
          return new VectorGraphicsImplSVG(container);
    
        // MS IE natively supports VML:
        if((navigator.userAgent.toLowerCase().indexOf("msie")
                                     != -1) && !window.opera)
          return new VectorGraphicsImplVML(container);
    
        return null;
      },
    
      ...
    }

    注意 1:Batik applet 的检测代码正在开发中。

    注意 2:请注意,Netscape 浏览器(截至 2007 年 7 月)既不支持 SVG 也不支持 VML。

  • SVG 启动细节

    1. 为了让 SVG 正确显示,必须满足以下条件

      • 宿主文档必须是有效的 XML 文档(例如,有效的 XHTML 页面);
      • SVG 根元素必须在 *http://www.w3.org/2000/svg* 的命名空间下定义。

      `_SetupRoot` 过程(此名称对所有实现者都是通用的)执行了使适当的解析器正常工作所需的所有启动任务。对于 SVG 实现者,它是:

      function VectorGraphicsImplSVG()
      {
        this._svgns = "http://www.w3.org/2000/svg";
        this._curX  = 0;
        this._curY  = 0;
        this._root  = null;
        this._cntr  = container;
        this._prep  = null;
      
        return this;
      }
      
      VectorGraphicsImplSVG.prototype = {
      
        // MSIE doesn't support createElementNS and
        // [get/set]AttributeNS, so we must take care:
        //
        _createElementNS: function(ns, name)
        {
          if(document.createElementNS)
            return document.createElementNS(ns, this._prep ?
                            (this._prep + ":" + name) : name)
          else
          {
            var elem = document.createElement(this._prep ?
                                (this._prep + ":" + name) : name);
            elem.setAttribute("xmlns", ns);
      
            return elem;
          }
        },
      
        _getAttributeNS: function(element, ns, name)
        {
          return (element.getAttributeNS ?
                  element.getAttributeNS(ns, name) :
                          element.getAttribute(name));
        },
      
        _setAttributeNS: function(element, ns, name, value)
        {
          if(element.setAttributeNS)
            element.setAttributeNS(ns, name, value);
          else
            element.setAttribute(name, value);
        },
      
        // SVG canvas setup:
        _SetupRoot: function()
        {
          if(this._root) return;
      
          if(VectorGraphics.prototype._CheckASV())
          {
            var obj = document.createElement("OBJECT");
            obj.setAttribute("id", "AdobeSVG");
            obj.setAttribute("classid",
                             "clsid:78156a80-c6a1-4bbf-8e6a-3cd390eeb4e2");
      
            document.getElementsByTagName("head")[0].appendChild(obj);
      
            document.namespaces.add("svg", this._svgns);
            document.namespaces("svg").doImport("#AdobeSVG");
      
            this._prep = "svg";
          }
      
          this._root = this._createElementNS(this._svgns, "svg");
          this._cntr.appendChild(this._root);
      
          this._setAttributeNS(this._root, null, "width",  "0");
          this._setAttributeNS(this._root, null, "height", "0");
        },
      
        ...
      
      }
    2. 为了使 SVG 代码生效,所有 XML 感知的浏览器都必须将下载的页面视为 XHTML,而不是 HTML。问题是 Microsoft IE 没有 XHTML 引擎;给定一个带有 XML prologue 的文档,它就像 XML 一样显示 - 作为节点的树。然而,构建跨浏览器 XHTML 的困境可以解决:

      • 不要使用任何 XML/XHTML prologues/DOCTYPEs;
      • 不要向客户端发送任何文档类型信息(但是:您可以使用服务器端浏览器检测将 *application/xhtml+xml* 发送给 Mozilla/Opera,将 *text/html* 发送给 Microsoft IE);
      • 依赖文件的扩展名;Mozilla 和 Opera 在页面扩展名为 *.xhtml* 时使用 XHTML 引擎,MSIE 在不满足 XML prologue 的情况下始终使用 HTML 引擎。

  • VML 启动细节

    1. 为了显示 VML,必须满足以下条件

      • 宿主浏览器必须是 Microsoft Internet Explorer;
      • 文档命名空间列表必须包含对 `urn:schemas-microsoft-com:vml` 的引用;
      • 宿主文档必须包含一个链接到 VML 行为的样式表:`behavior: url(#default#VML);`;
      • 必须定义 VML 根元素,并指定坐标大小和原点。

      所有这些任务都由以下 `_SetupRoot` 过程完成:

      function VectorGraphicsImplVML()
      {
        this._curX = 0;
        this._curY = 0;
        this._root = null;
        this._cntr = container;
      
        return this;
      }
      
      VectorGraphicsImplVML.prototype = {
      
        // VML canvas setup:
        _SetupRoot: function()
        {
          if(this._root) return;
      
          // Add VML style definition:
          var stl = document.createStyleSheet();
          stl.addRule("v\\:*", "behavior: url(#default#VML);");
      
          // Add xml namespace definition:
          document.namespaces.add("v",
                   "urn:schemas-microsoft-com:vml");
      
          var root = document.createElement("v:group");
          root.style.width  = this._cntr.offsetWidth;
          root.style.height = this._cntr.offsetHeight;
          root.coordorigin  = "0,0";
          root.coordsize    = this._cntr.offsetWidth + "," +
                              this._cntr.offsetHeight;
      
          this._root = this._cntr.appendChild(root)
        },
      
        ...
      
      }
    2. 使 XHTML 在任何地方都能工作的解决方案在前面已经描述过。只需记住格式良好和其他 XHTML 语法规则。

  • 用法

    使用该库非常简单

    <script type="text/javascript" src="svg+vml.js"></script>
    <script type="text/javascript">
    
       function Draw()
       {
         var vg = new VectorGraphics(document.getElementById("container"));
    
         vg.SetStrokeColor("black");
         vg.SetStrokeWidth(1);
    
         // rectangle #1:
         vg.MoveTo(100, 100);
         vg.SetFillColor("green");
         vg.Rect(100, 100);
    
         // inner squares:
         vg.MoveTo(105, 105);
         vg.SetFillColor("#ADFF2F");
         vg.Rect(10, 10);
         vg.MoveTo(120, 105);
         vg.SetFillColor("#7CFC00");
         vg.Rect(10, 10);
         vg.MoveTo(135, 105);
         vg.SetFillColor("#32CD32");
         vg.Rect(10, 10);
         vg.MoveTo(105, 120);
         vg.SetFillColor("#3CB371");
         vg.Rect(10, 10);
         vg.MoveTo(105, 135);
         vg.SetFillColor("#2E8B57");
         vg.Rect(10, 10);
    
         // green cross:
         vg.Polygon([[195,85],[205,85],[205,95],[215,95],[215,105],[205,105],
            [205,105],[205,115],[195,115],[195,105],[185,105],
            [185,95],[195,95]]);
    
         // supporter lines:
         vg.MoveTo(100, 205);
         vg.SetStrokeColor("#708090");
         vg.LineTo(200, 205);
         vg.LineTo(320, 320);
         vg.LineTo(543, 320);
    
         vg.SetStrokeColor("black");
    
         vg.SetFont("Arial Unicode MS", 16, "blue", "normal");
    
         // text:
         vg.MoveTo(321, 315);
         vg.Text("Some Not So Long Blue Text");
    
         // rectangle #2:
         vg.MoveTo(100, 240);
         vg.SetFillColor("#FF4500");
         vg.Rect(100, 100);
    
         vg.MoveTo(105, 245);
         vg.SetFillColor("#F08080");
         vg.Rect(10, 10);
         vg.MoveTo(120, 245);
         vg.SetFillColor("#CD5C5C");
         vg.Rect(10, 10);
         vg.MoveTo(135, 245);
         vg.SetFillColor("#FF0000");
         vg.Rect(10, 10);
         vg.MoveTo(105, 260);
         vg.SetFillColor("#B22222");
         vg.Rect(10, 10);
         vg.MoveTo(105, 275);
         vg.SetFillColor("#8B0000");
         vg.Rect(10, 10);
    
         // blood cross:
         vg.Polygon([[195,225],[205,225],[205,235],
                [215,235],[215,245],[205,245],
                [205,245],[205,255],[195,255],
                [195,245],[185,245],[185,235],[195,235]]);
    
         vg.MoveTo(100, 345);
         vg.SetStrokeColor("#90A0B0");
         vg.LineTo(200, 345);
         vg.LineTo(320, 345);
         vg.LineTo(535, 345);
    
         vg.MoveTo(321, 340);
         vg.Text("Another Not So Long Blue Text");
    
         vg.SetStrokeColor("black");
    
         // rectangle #3:
         vg.MoveTo(100, 400);
         vg.SetFillColor("#FFD700");
         vg.Rect(100, 100);
    
         vg.MoveTo(105, 405);
         vg.SetFillColor("#FFFF00");
         vg.Rect(10, 10);
         vg.MoveTo(120, 405);
         vg.SetFillColor("#FF8C00");
         vg.Rect(10, 10);
         vg.MoveTo(135, 405);
         vg.SetFillColor("#B8860B");
         vg.Rect(10, 10);
         vg.MoveTo(105, 420);
         vg.SetFillColor("#FFA500");
         vg.Rect(10, 10);
         vg.MoveTo(105, 435);
         vg.SetFillColor("#D2691E");
         vg.Rect(10, 10);
    
         // yellowish cross:
         vg.Polygon([[195,385],[205,385],[205,395],
                [215,395],[215,405],[205,405],
                [205,405],[205,415],[195,415],
                [195,405],[185,405],[185,395],[195,395]]);
    
         vg.MoveTo(100, 505);
         vg.SetStrokeColor("#B0C0D0");
         vg.LineTo(200, 505);
         vg.LineTo(320, 370);
         vg.LineTo(542, 370);
    
         vg.MoveTo(321, 365);
         vg.Text("Final Not So Long Blue Text");
    
         vg.SetStrokeColor("black");
    
         // circles:
         vg.MoveTo(585, 345);
         vg.SetFillColor("#DA70D6");
         vg.Ellipse(50, 100);
         vg.SetFillColor("#BA55D3");
         vg.Ellipse(40, 80);
         vg.SetFillColor("#9932CC");
         vg.Ellipse(30, 60);
         vg.SetFillColor("#8B008B");
         vg.Ellipse(20, 40);
         vg.SetFillColor("#800080");
         vg.Ellipse(10, 20);
       }
    </script>

  • 扩展库

    您可能希望扩展该库以支持任何其他 API。为了能够使用支持 PGML 的浏览器进行绘图,您需要更改多少?非常少:

    • 定义一个新的 `VectorGraphicsImplPGML` 对象及其方法
      function VectorGraphicsImplPGML(container)
      {
         this._curX = 0;
         this._curY = 0;
         this._root = null;
         this._cntr = container;
      
         ...
      }
      
      VectorGraphicsImplPGML.prototype = {
      
        LineTo: function(x, y, stroke_color)
        {
          if(!this._root) this._SetupRoot();
      
          ...
        },
      
        Rect: function(width, height, fill_color)
        {
          if(!this._root) this._SetupRoot();
      
          ...
        },
      
         ...
      }
    • 在 `VectorGraphics.prototype._EstablishImplementor` 中添加一个新的条件路径。
      _EstablishImplementor: function(container)
      {
        // Browsers/plugins that support SVG:
        if((navigator.mimeTypes &&
           (navigator.mimeTypes["image/svg+xml"] ...)))
      
          return new VectorGraphicsImplSVG(container);
      
        // Browsers/plugins that support PGML:
        else if(navigator.mimeTypes &&
      
                   navigator.mimeTypes["image/pgml+xml"])
      
          return new VectorGraphicsImplPGML(container);
      
        else
        {
          ...
        }
      
        ...
      }

后记

我很想听听您的想法。如果您有任何问题和/或建议,请随时给我发电子邮件

链接

推荐阅读

  • Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 的《设计模式:可复用面向对象软件元素》
    Addison-Wesley,1995。 ISBN 0-201-63361-2
  • Nicholas C. Zakas 的《专业 Web 开发人员 JavaScript》Wiley Publishing Inc.,2005。 ISBN 0-7645-7908-8

Web

历史

  • 2006 年 9 月 20 日 - 首次发布
  • 2006 年 10 月 2 日 - 文章修订,代码更新以支持 Adobe SVG 插件
  • 2006 年 11 月 16 日 - 文章更新
  • 2006 年 12 月 20 日 - 源代码修订,文章更新
  • 2007 年 7 月 26 日 - 源代码修订,文章更新
© . All rights reserved.