Dojo.gfx包分析

 
Dojo.gfx包分析
2006-12-22
 
修订:
2007-01-08:更正对attach的描述,改“拷贝”为“引用”
1.     背景
由于目前在主流浏览器之间没有一个标准的WEB2D矢量图形技术,特别是在IE没有内置支持SVG之前,WEB开发人员一直以来都在寻找一个能够跨平台的解决方案。在INTERNET上不难发现很多人都在这方面进行着不懈的努力。其主要的方向是:
一,比较简单的方法是使用javascript实现几种图形技术之间的转换,特别是SVG到VML;
二,通过实现一个与实际渲染器无关的中间层来实现在不同浏览器上的矢量图形显示和处理。
 
这些实现包括:
  • ExplorerCanvas
  • RichDraw
  • jsVectorGraphics
  • jsDrawing
  • Dojo.gfx
  • Cumulate Draw
 
其中dojo.gfx就是通过一个抽象图形中间层,实现跨浏览器的图形显示。dojo.gfx在0.4版本中增加,目前还处于发布初期,接口函数和实现方法在将来还可能调整改变,但已经实现了大多数矢量图形的功能(不包括文本,clip和filter等高级功能)。
 
2.     gfx相关文件
打开dojo源文件中gfx目录可以发现以下文件:
文件或文件夹
作用
_package__.js
通配符包含的文件声明(dojo.gfx.*)
Common.js
抽象图形类,包括surface
Shape.js
抽象图形类,包括shape(基类), rect, line, ellipse, circle, polyline, image和group
Vml.js
对抽象图形类的VML相关实现以及对path的重载实现
Svg.js
对抽象图形类的SVG相关实现
Path.js
路径类
Matrix.js
坐标矩阵类
Color.js
色彩类
Colorspace.js
不同的色彩表示方法之间的转换
Color 文件夹
色彩相关设置
 
在目前的版本中没有发现针对Canvas的实现,在dojo的某些文档中提到由于Canvas的实现机制与SVG差别较大,因此被删除了。另外,在dojo.gfx中没有对text对象的支持,由于text实现的难度比较大,可能在后续版本中增加,这对目前的使用不能不说是个缺憾了。
       用户在使用gfx包时,仅仅需要关心在Common.js,Shape.js,Path.js和Matrix.js中的抽象接口类,而不需要了解Vml.js和Svg.js中的各抽象类的具体实现。下面就讨论一下抽象接口层中的gfx类及其属性和方法。
 
3.     gfx图形类
Dojo.gfx中的类基本分两种,与渲染器相关的类和与渲染器无关的类。所谓渲染器就是针对不同浏览器支持的矢量图形引擎,例如SVG,VML和Canvas
3.1.   与渲染器相关的类
与渲染器相关的类包括Path, Shape, Group, Surface,其中Shape下包括子类rect, line, ellipse, circle, polyline, image。这些图形对象都对应一个抽象类和实际渲染器的实现类。以下列出其属性和方法(私有属性和方法命名以“_”开头),可能没有列全,需要的可以查看其JS源代码。
 
(原文中为UML图形,但现在CSDN BLOG无法上图,只能以后再补了 :(    )
dojo.gfx.Shape
抽象图形基类,其属性取决与具体的图形子类,方法包括
 
setStroke                   设置笔画
setFill                        设置填充
_applyTransform       坐标变换,与setTransform不同,是一种增量变换
setRawNode            设置节点数据
moveToFront             在图层中移动到最前面
moveToBack              在图层中移动到最后面
setShape                    设置图形
attachFill                    引用使用已有的填充对象
attachStroke                     引用使用已有的笔画对象
attachTransform          引用使用已有的变换矩阵对象
attachShape                引用使用已有的图形形状对象
attach                        引用使用已有的图形(包括其笔画,形状,填充和坐标矩阵对象等)
 
       下列图形从Shape继承而来,其属性和方法基本同Shape类,不再作详细描述,具体使用方法参见第四节。
rect
矩形
 
line
直线
 
ellipse
椭圆(当rx=ry 时为圆)
 
circle
圆弧
 
polyline
多边形
 
image
光栅图形,可以为BMP,JPG,PNG 和GIF
 
virtualGroup/group
图形组
add                 在组中增加图形
remove            在组中删除图形
 
对组的操作举例
var g1 = surface.createGroup();
var g2 = g1.createGroup();
g1.add(line);
g1.remove(line);
g1.add(g2)
 
path
路径
setAbsoluteMode
getAbsoluteMode
getBoundingBox
getLastPosition
moveTo                         M  m
lineTo                            L   l
hLineTo                        H  h
vLineTo                         V   v
curveTo                         C
smoothCurveTo          S
qCurveTo                      Q
qSmoothCurveTo        T
arcTo                             A
closePath                     Z
setShape
熟悉SVG或VML对上面的标记也比较了解,就不一一解释了。 
 
3.2.   与渲染器无关的类
与渲染器无关的类包括Fill, Stroke和Matrix,分别对应图形类中的填充,笔画和坐标属性。
 
填充对象
填充对象描述了图形的不同填充方式。根据填充类型的不同,填充对象的属性数量和种类也不同。Fill 对象现在支持三种填充方式,包括线性渐变填充linearGradientFill,圆形渐变填充radialGradientFill和图案填充PatternFill,其中图案填充不一定被所有浏览器支持(例如目前版本的FireFox)。
 
l         线性渐变
var lg = {
                     type: "linear",
                     x1: 0, y1: 0, x2: 75, y2: 50,
                     colors: [
                            { offset:   0, color: "#F60" },
                            { offset:   0.5, color: "#FAF" },
                            { offset:   1, color: "#FF6" }
                     ]
              };
 
var ref = surface.createRect(rect)
        .setFill(lg)
;
 
l         圆形渐变
var rg = {
                     type: "radial",
                     cx: 100, cy: 100, r: 100,
                     colors: [
                            { offset:   0, color: "red" },
                            { offset: 0.5, color: "green" },
                            { offset:   1, color: "blue" }
                     ]
              };
 
       var circle = {cx: 100, cy: 100, r: 100 };
       var ref = surface.createCircle(circle)
            .setStroke({color: "blue", width: 1 })
            .setFill(rg)
                     .setTransform({dx: 40, dy: 30})
            ;
 
l         图案填充
var pattern = {
            type: "pattern",
            x: 0, y: 0, width: 120, height: 96,
            src: "http://dojotoolkit.org/img/viewcvs.png"
        };
 
        var ellipse = {cx: 150, cy: 100, rx: 150, ry: 100};
        var ref = surface.createEllipse(ellipse)
            .setStroke({color: "blue", width: 1 })
            .setFill(pattern)
            ;
 
笔画对象
笔画对象描述了不同笔画风格,包括颜色,宽度和连接方式。
dojo.gfx.createStroke(color, width, cap, join)
 
返回一个笔画对象,其中Cap可以为"butt", "round", 或 "square". Join 可以为"round", "bevel", 或者一个倾斜数值. Cap 和 join为可选属性。
var points = [ {x:70, y:15}, {x:40, y:70}, {x:100, y:80}, {x:130, y:-20}];
       var ref = surface.createPolyline(points)
         .setStroke({color:[255, 0, 0, 0.7], width:1});
 
矩阵对象
       矩阵对象描述了图形的坐标对象,通过改变图形的坐标矩阵可以完成对图形的平移,旋转,缩放和歪斜等变换。矩阵对象的属性包括 xx, xy, yx, yy, dx, dy,熟悉SVG变换矩阵的都知道其坐标变换公式:
(图)
 
通过变换矩阵的操作就可以实现图形的坐标变换,而dojo中的matrix对象就是SVG的变换矩阵,其中xx = a; xy=b; yx=c; yy=d; e=dx; f=dy。
变换矩阵的操作包括:
translate 平移
scale 放大
scaleAt 定点放大
rotate 旋转
rotateg 按角度旋转
rotateAt 定点旋转
rotategAt 按角度定点旋转
 
skewX X歪斜
skewXg 按角度X歪斜
skewY Y歪斜
skewYg 按角度Y歪斜
skewXAt 定点X歪斜
skewYAt 定点Y歪斜
skewXgAt 定点按角度X歪斜
skewYgAt 定点按角度Y歪斜
 
normalize 单位化
clone 克隆
invert 翻转
 
_multiplyPoint 对坐标点的矩阵变换
multiplyPoint 对坐标点的矩阵变换
multiply 矩阵相乘
 
_sandwich 定点实施矩阵变换
 
坐标变换应用
           var circle = {cx: 100, cy: 100, r: 100 };
              var ref = surface.createCircle(circle)
                     .setTransform({dx: 40, dy: 30});
或者
       circle.setTransform(dojo.gfx.matrix.translate(40,30));
4.     使用
4.1.   基本使用
使用dojo.gfx包步骤
1, 包含dojo.gfx包
dojo.require("dojo.gfx.*");
 
2, 设置和取得容器节点,一个容器是一个HTML节点,gfx的内容就放置在相应的容器下。
在HTML的BODY中:
<div id="test" style="width: 500px; height: 500px;"></div>
在脚本中:
gTestContainer = dojo.byId("testcontainer");
 
3, 建立画布surface,对SVG对应的是<svg>节点,而VML中为<v:group>,画布类使用基本图形类,dojo会根据浏览器类型自动选择可用的渲染器,并建立相应的surface对象。
surface = dojo.gfx.createSurface(gTestContainer, 500, 500);
 
4, 建立各种图形对象并设置参数,可以采用两种方式,一是直接使用createObject
dojo.gfx.createObject(dojo.gfx.Line, line);
更简单明确的方法是使用dojo.gfx._creators提供的函数,例如dojo.gfx.createLine。以下是各种图形的创建示例。
 
l         矩形
var rect = { x: 0, y: 0, width: 100, height: 30 };
var red_rect = surface.createRect(rect);
 
l        
var circle = { cx: 130, cy: 130, r: 50 };
              var ref = surface.createCircle(circle)
            .setFill([0, 255, 0, 0.7])
            .setTransform({ dx: 20, dy: 20 })
            ;
或直接传入对象创建(也适用于其它图形)
var aShape = surface.createCircle({cx: cx, cy: cy, r: r})
                     .setFill(randColor(true))
                     .setStroke({color: randColor(1), width: getRand(3)})
                     ;
 
l         直线
var line = { x1: 0, y1:0, x2:80, y2:80 };
              var ref = surface.createLine(line)
            .setFill([0, 255, 0, 0.7])
            .setStroke({color:[0, 0, 255, 0.7], width:3} )
            .setTransform({ dx: 20, dy: 20 })
            ;
 
l         多边形
var points = [ {x:70, y:15}, {x:40, y:70}, {x:100, y:80}, {x:130, y:-20}];
              var ref = surface.createPolyline(points)
            .setFill([0, 255, 0, 0.7])
            .setStroke({color:[255, 0, 0, 0.7], width:1})
            .setTransform({ dx: 50, dy: 20 })
            ;
 
l         路径,单独定义在path.js中
var re1 = g1.createPath()
              .moveTo(startPoint)
              .arcTo(rx, ry, xRotg, true, false, endPoint)
              .setStroke({color: "red"})
              ;
当然也可以使用路径字符串创建路径
var path=surface
              .createPath("M100 100 200 100 200 200C200 250 150 250 100 200S50 100 100 100z")
              .setStroke({color: "blue"})
              .setFill("#ddd")
              .setTransform({dx: 100, dy: -50})
 
l         图像
image = surface.createImage({width: 319, height: 95,
src: "http://dojotoolkit.org/img/header-downloads.png"});
 
5, 图形的引用和删除
 
使用attach方法可以使用已经存在的图形对象,在attach中包括以下操作:
//元素
 引用节点               this.rawNode = rawNode;
 
//属性
 引用填充               this.fillStyle = this.attachFill(rawNode);
 引用线形               this.strokeStyle = this.attachStroke(rawNode);
 引用变换矩阵        this.matrix = this.attachTransform(rawNode);
 引用图形               this.shape = this.attachShape(rawNode);
 
在使用attach前应创建和源对象类型相同的图形对象,而使用attachNode方法可以自动判断源节点的类型,并生成相应的新节点,然后调用attach拷贝源节点的图形。例如:
var ar = dojo.gfx.attachNode(ref.rawNode);
 删除节点(没有正式的解答,dojo interesting中有人建议以下方法,测试后可以使用,不知是否对所有情况适用)
Gavin Doughtie wrote:
> mySurface.rawNode.removeChild(myPath.rawNode);
> should work, but it seems wrong. Euguene -- I don't see API for this.
> What's your suggestion?
6, 关联事件
各种图形可以关联鼠标和键盘事件,例如在图形上关联鼠标点击事件
image = surface.createImage({width: 319, height: 95,
src: "http://dojotoolkit.org/img/header-downloads.png"});
dojo.event.connect(image.getEventSource(), "onclick", function(){ alert("You didn't expect a download, did you?"); });
 
4.2.   图形的拖放
gfx图形的拖放不能使用dojo中的dnd,要通过gfx容器的事件处理完成。
 
1,设置gfx容器的鼠标处理事件
       dojo.event.connect(container, 'onmousedown', onGrab);
       dojo.event.connect(container, 'onmousemove', onDrag);
       dojo.event.connect(container, 'onmouseup',   onDrop);
 
2,建立图形并设置ID
       aShape.getEventSource().setAttribute('shapeid', id);
       //要设置相应的CSS属性,这对消除VML移动障碍非常重要
       dojo.html.setClass(aShape.getEventSource(), "movable");
       gShapes[id] = aShape;
 
3,根据ID属性得到图形对象
function getShape(event)
{
       var id = event.target.getAttribute('shapeid');
       var s = id ? gShapes[id] : null;
       return s;
}
 
4,完成处理事件
function onGrab(event)
{
       var shape = getShape(event);
       if (shape) {
              current_shape = shape;
              current_shape.moveToFront();
              last_position = {
                     x: event.clientX ,
                     y: event.clientY
              };
       }
       //dojo.event.browser.stopEvent(event);
}
 
function onDrag(event)
{
       if(!current_shape)
              return;
             
       var x = event.clientX - last_position.x;
       var y = event.clientY - last_position.y;
       current_shape.applyTransform({dx: x, dy: y});
      
       last_position = {
                     x: event.clientX ,
                     y: event.clientY
              };
                    
       //dojo.event.browser.stopEvent(event);
}
 
function onDrop(event)
{
       current_shape = null;
       //dojo.event.browser.stopEvent(event);
}
 
参考资料
       Dojo Book和例子
       Dojo Interesting Forum
       http://www.thinkvitamin.com/features/design/create-cross-browser-vector-graphics
 

你可能感兴趣的:(function,浏览器,image,dojo,图形,colors)