Master DOJO Toolkit

Dojo as One of the most famous Ajax open source projects not only allows web programmers to obtain and use its framework for web application development for free, but also attracts a large number of developers to continuously expand it and develop new components. DojoX was born in such a development community. DojoX is a collection of dojo-based open source projects, these open source projects have very good ideas and high practicality. These DojoX projects may grow into a stable version and remain in DojoX, and some may be migrated to Dojo Core or Dijit. This article will give a general overview of the projects in DojoX and introduce some of the more distinctive projects with examples. This article will mainly introduce DataGrid, Charting, Gfx/Gfx 3D and DojoX Widget.

Get to know DojoX

Currently The DojoX project mainly extends data structures and algorithms, data processing and communication, utility tools, graphics APIs, and Web UI.

Projects involving data structures and algorithms include DojoX Collections, DojoX Encoding, etc. Collections defines many very useful data collections, including ArrayList, BinaryTree, Dictionary, Iterator, Queue, SortedList, Stack. The use of these sets will greatly improve the efficiency of program development and the quality of the program. Encoding not only provides string and character encoding conversion, but also provides symmetric algorithm Blowfish and MD5 digital digest algorithm.

DojoX Data, Embed, I/O, JSON, XML, RPC, etc. extend Dojo’s data processing and communication capabilities. Among them, the Data project provides support for more data formats, including support for csv files and APIs provided by Google, Picasa, and so on.

DojoX’s graphics API extends Dojo’s animation effects and provides 2D and 3D drawing support. DojoX Fx provides a variety of animation effects through extensions to dojo core and dojo fx; gfx provides a series of vector drawing methods; and gfx3d provides some simple 3D drawing APIs.

Richer Web UI and Web widgets are also a highlight of DojoX. The powerful Grid, practical Charting, DojoX Image and DojoX Layout make the Web UI developed based on dojo richer. DojoX Widgets also provides richer widgets to meet the needs of most application development.

In addition to the items introduced above, DojoX also collects many useful tools, readers can get more on the dojo API website Information. http://api.dojotoolkit.org/

Next, let’s experience what DojoX brings to us

Note: The dojo version used in this tutorial is 1.2.1, due to the dojo and dojoX components in the 1.2.x version There are major changes, so this article is only applicable to dojo1.2.x, for dojo1.0 developers, this article is for reference only, and some codes cannot run correctly

DojoX DataGrid

Grid may be the most popular component in DojoX. Compared with ordinary Web form components, Grid is more like a Web-based Excel component. This allows Grid to cope with more complex data display and data manipulation. In dojox1.2, the DataGrid class is added to the dojox.grid package. This class is an enhancement and replacement of the original Grid class. It is called DataGrid because it is seamlessly integrated with the dojo data manipulation class store. . The previous Grid needs to package the store object as a model object before it can be used. If there is no special statement below, all Gird or DataGrid refers to the new version of DataGrid, not Grid1.0.

Figure 1 .DojoX DataGrid

Figure 1 .DojoX DataGrid

Why do we need Grid? The features of Grid are listed below:

  • Users only need to drag the scroll bar down, and the Grid can load delayed records, eliminating the need for page turning Operation, reduce the interaction between the Web and the server, and improve the performance;
  • You can add and delete cells, rows, or columns arbitrarily;
  • Perform statistical summary on rows, and Grid can generate reports similar to OLAP analysis;
  • Grid goes beyond the function of a two-dimensional table, it can Combine cells across rows or columns to meet different data filling needs;
  • The row and column freeze function makes browsing data more Flexible and convenient;
  • The Grid event uses a hook mechanism. We can use the onStyle hook to change the style;
  • The cell has rich operations, all dijit components can be used in the cell, and the cell can be converted to edit state by clicking;< /li>
  • can be Set different context menus for different cells;
  • Grid nesting, which means that Grid can nest other Grids in cells to form more complex applications;

In addition, Grid also has many other features, such as very useful even-numbered row coloring, flexible selection function, automatic adjustment of column width, data expansion/closing and so on.

DataGrid basics< /span>

To create a DojoX DataGrid, you need to have a general understanding of the basic working process of the DataGrid. The composition structure of a DataGrid instance is shown in the following figure. DojoX DataGrid is the basis of using DataGrid, so when using Grid, you need to load related dojox packages; a widget usually consists of a frame and style, so we need to specify the style of DataGrid Table and declare the DataGrid instance. The DataGrid instance will combine a Structure and a Store. Structure is the definition of a header and data model, and Store is used to carry data.

Figure 2 .DataGrid composition structure

Figure 2 .DataGrid composition structure

Let’s start our first DataGrid application. To create a DataGrid widget on a Web page, we start with the most basic two-dimensional table. First, we need to load some styles to ensure that the DataGrid can display normally, as shown in Listing 1.

Listing 1 . Loading style
 

here The css file path is relative to the test page.

Before starting to create Grid, we have to introduce Dojo’s basic package dojo.js to load other needs dojo class, and load dojo.data.ItemFileReadStore class and dojox.grid.DataGrid class. Next we can proceed to develop the first DataGrid. The first is the definition of the layout, such as Listing 2

Listing 2. Define the layout
 var layout = [{field:'pro_no', name:'Product Number' }, {field:'pro', name:'Product' }, {field:'min_amount', name :'Minimum Amount' }, {field:'max_amount', name:'Maximum Amount' }, {field:'avg_amount', name:'Average Amount'} ];

An array layout is defined here, where each member represents the definition of a column, and the field specifies the data item used. The value needs to follow the javascript variable definition rules; name is the name displayed in the column. Next is the development of the store. The code is shown in Listing 3

Listing 3. Developing store
 var sampleData = {identifier:'pro_no', label:'pro_no', items: [{pro_no:'2100', pro:'A Series', min_amount:346, max_amount: 931, avg_amount:647}, {pro_no:'2200', pro:'B Series', min_amount:301, max_amount:894, avg_amount:608}, {pro_no:'2300', pro:'C Series', min_amount: 456, max_amount:791, avg_amount:532} , {pro_no:'2400', pro:'D Series', min_amount:859, max_amount:2433, avg_amount:1840}, {pro_no:'2500', pro:'E Series', min_amount:459, max_amount:1433, avg_amount:1040}] }; var jsonStore = new dojo.data.ItemFileReadStore({ data: sampleData });

Here, we first define a JSON data sampleData, where identifier is the unique identifier for the entire row, so there can be no repetitions in the data; the array items is the data displayed in this table, and the data must completely conform to the JSON syntax , Quotes must be used at both ends of the string, otherwise grammatical errors will occur. The safe way is to enclose all values ​​in quotation marks.

Next, we will define the DataGrid instance in the Body element of the web page, as shown in Listing 4

< h5 id="code4" style="margin:5px 0px 0px; padding:0px; border:0px; outline:0px; font-size:1.166em!important; vertical-align:baseline"> Listing 4. Define DataGrid instance< /h5>

 

dojoType specifies that the web part is dojox. grid.DataGrid, the data uses jsonStore, the structure is layout, and the width is automatically adjusted. At this point, the first Grid has been developed. The complete code is shown in Listing 5

Listing 5. Complete code
   first Grid     < /head>  
Fi rst Grid

Run in the browser, the effect is as follows:

Figure 3. The results of the first grid operation

< img alt="Figure 3. The first Grid running result" src="/wp-content/uploadshttp:/img.voidcn.com/vcimg/static/loading.png" width="382" style="margin:0px ; padding:0px; border:0px; outline:0px; font-size:undefined; vertical-align:baseline" d="2891159" s="9bc_7cd" t="jpg">

Detailed Explanation of DataGrid Development

DataGrid creation

In the development of DataGrid, there are three ways to create DataGrid instance, the first is javascript to create structure, html code to create instance, our first example is Realized in this way;

The second is to create structures and examples from html code. In this method, we Use the table tag to define the structure of the Grid, and omit the part of defining the structure in javascript. The specific definition method is very similar to the standard html writing method, as shown in Listing 6

Listing 6. Create structure and examples from html code
 
Product Number Product Minimum Amount Max imum Amount Average Amount

The third method is to use pure javascript to define the DataGrid instance. Listing 7 declares that after the web page is loaded, it will create a DataGrid instance on the page node whose id is gridNode.

Listing 7 . DataGrid instance defined in pure javascript
 dojo.addOnLoad(function(){ // execute after the specified page is loaded var grid = new dojox.grid.DataGrid({ query: {pro_no:'*' }, id:'grid2', store: jsonStore, structure: [{field:'pro_no', name:'Product Number' }, {field:'pro', name:'Product' }, {field:'min_amount', name:'Minimum Amount' }, { field:'max_amount', name:'Maximum Amount' }, {field:'avg_amount', name:'Average Amount'} ],rowsPerPage: 20 },'gridNode'); // Set the grid to be displayed under the node whose id is gridNode grid.startup( ); // Start the grid });

Grid1.2 can be easily compared with Dojo containers are combined to dynamically create page layouts.

Structure details

DataGrid can not only create simple two-dimensional tables, You can also create complex table applications by designing the structure, and you can also format or take values ​​for each column. We simply modify First Grid to get the code in Listing 8.

Listing 8 . Modify First Grid
 function formatAmount(value){ return'$ '+ value;} function getRange(rowIndex, item){ if(!item){return'--';} var grid = dijit.byId('grid'); var max = grid.store.getValue(item, "max_amount"); var min = grid.store.getValue(item, "min_amount"); return max-min;} var subrow1 = [{field:'pro_no', name: ' Product N umber', rowSpan: 2 }, {field:'pro', name:'Product', rowSpan: 2 }, {field:'min_amount', name:'Min. Amount',formatter: formatAmount,width: '80px' }, {field:'avg_amount', name:'Average Amount',formatter: formatAmount, rowSpan: 2 }, {field:'range', name:'Range',get:getRange, rowSpan: 2} ]; var subrow2 = [{field:'max_amount', name:'Max. Amount',formatter: formatAmount}, ]; var layout = [subrow1,subrow2];

Here, we have redefined the layout and divided the layout into two sub-rows. Sub-row 1 contains five fields, among which pro_no, pro, avg_amount and range have the value 2. The rowSpan property of, also shows that these three columns span two rows. The second line has only one field max_amount. At the same time, we specified the formatter function for the three amount fields, adding a dollar sign in front of their values. The get method is specified for the range field to automatically obtain the difference between the maximum value and the minimum value.

The display effect is as follows:

Figure 4. DataGrid layout example 1

Figure 4. DataGrid layout example 1

Except In addition to the rowSpan attribute, we can also use the colSpan attribute. The usage of these two attributes is consistent with the usage in html, and can be used in the html definition table structure. Let’s look at this header example to understand the usage of colSpan.

Listing 9 . colSpan application
 var structure = [[ {field:'type', name:'Type', rowSpan: 2}, {field:'pro', name:'Product', rowSpan: 2}, {field:'Q20071', name :'Q1',formatter: formatAmount }, {field:'Q20072', name:'Q2',formatter: formatAmount }, {field:'Q20073', name:'Q3',formatter: formatAmount }, {field: ' Q20074', name:'Q4',formatter: formatA mount} ],[ {field:'Y2007', name:'Year 2007',formatter: formatAmount, colSpan: 4} ]];

The display effect of Listing 9 is as follows:

Figure 5. DataGrid layout example 2

Figure 5. DataGrid layout example 2

Use of Store

DataGrid Store is used as the data source. In the above example, we write the data in javascript and pass it to the store construction method as the data parameter value. But in most cases, the data is dynamically obtained from the server through Ajax requests, which can also be achieved through the Store. We only need to pass in the requested url address when declaring the Store object, such as: new dojo.data.ItemFileReadStore({url:’jsondata.txt’ }). Store includes two classes, dojo.data.ItemFileReadStore and dojo.data.ItemFileWriteStore. When we use the editing function of the DataGrid, we need to use ItemFileWriteStore as the data source. The following demonstrates a multi-functional DataGrid. This Grid uses an external data source to edit cells and pop-up a column selection menu by right-clicking on the header of the table. In order for the page to be correct, Listing 10 loads the required CSS.

Listing 10 . Load the required CSS
 

清单 11的代码引入了所需的 dojo 包,并创建了可编辑的 DataGrid,将其添加到了 id 为 gridNode 的页面节点中。 In order to make the column editable, you only need to add an editable attribute with a value of true to the JSON definition of the column in the structure definition.

清单 11. 引入所需 Dojo 包
   

清单 12定义了菜单 gridMenu 以及承载 DataGrid 的 DIV。

清单 12. 定义菜单
   
Data Grid

本例使用了外部数据源 dataGrid.txt,该文件的内容类似于 清单 13

清单 13. dataGrid.txt
 { 	 identifier: 'emp_no', 	 label: 'emp_no', 	 items: [      {emp_no:'2100', name:'Matt', gender:'M', dept_no:730, bonus:647}, 	 { emp_no:'2200', name:'Lisa', gender:'F', dept_no:731, bonus:608}, 	 {emp_no:'2300', name:'Mick', gender:'M', dept_no:732, bonus:532}, 	 {emp_no:'2400', name:'John', gender:'M', dept_no:733, bonus:1840}, 	 {emp_no:'2500', name:'Jan', gender:'M', dept_no:734, bonus:1040}, 	 {emp_no:'2101', name:'Jeff', gender:'M', dept_no:730, bonus:647}, 	 {emp_no:'2202', name:'Frank', gender:'M', dept_no:731, bonus:608}, 	 {emp_no:'2303', name:'Fred', gender:'M', dept_no:732, bonus:532}  ]}

运行,结果如下图所示。

图 6. 可编辑的 DataGrid

图 6. 可编辑的 DataGrid

DojoX Charting

Charting 是基于 DojoX 绘图包的数据可视化组件,包括了 Chart2D 和 Chart3D 来分别绘制 2D 和 3D 的图表。 Chart2D 提供多种样式的饼图、柱状图、折线图、面积图、网格等图表。 Chart3D 目前仅提供了 3D 柱状图和 3D 圆柱图,并且从社区获取的信息表明由于 IE 上的性能问题导致 Chart3D 的开发暂时搁置。 Charting 的应用主要分为如下几个步骤:

  1. 首先引入所需要的 dojox 类,如:
    dojo.require(“dojox.charting.Chart2D”); //Chart2D 所需要的 2D 类 
    dojo.require(“dojox.charting.Chart3D”); //Chart3D 所需要的 3D 类 
    dojo.require(“dojox.charting.themes.PlotKit.blue”); // 样式主题
  2. 第二,声明 Chart 对象,包括了 Chart2D 或 Char3D,
    如:var chart1=new dojox.charting.Charting.Chart2D(‘chart1’);
    这里传入的参数为要在页面中载入 chart1 的元素的 ID,也就是 chart1 显示后的上层标签的 ID;
  3. 使用 Chart 对象的 setTheme 为 Chart 对象设置主题,来保证准确的绘制图表;
  4. 使用 Chart 对象的 addPlot 方法为 Chart 对象添加部件,可以添加多个部件;
  5. 使用 Chart 对象的 addSeries 方法为 Chart 对象添加数据;
  6. 最后,调用 render 方法将 chart 对象添加到页面节点中;

下面我们来看几个应用实例。

2D 饼图

清单 14的代码为 2D 饼图,我们可以看到该实例加载了类 Chart2D 和 themes.PlotKit.blue 对象。 chart1 对象声明在 ID 为 char1 的元素下,并被添加了一个 Pie 部件作为默认部件,数据为 3、2、5、1、6、4。

清单 14.2D 饼图
  …… 

运行结果如下:

图 7. 二维饼图示例

图 7. 二维饼图示例

带网格的 2D 面积图

这个例子中我们为 Chart2D 对象添加了两个部件,网格和面积图,如 清单 15。值得注意的是,我们为 chart 添加了两个部件,Plot1 和 Plot2,其中 Plot1 的类型为 Areas,Plot2 的类型为 Grid,我们给 Plot1 添加了三组数据,并没有给 Plot2 添加数据。

清单 15. 网格和面积图
 chart = new dojox.charting.Chart2D("chart2");  chart.setTheme(dojox.charting.themes.PlotKit.orange);  chart.addAxis("x", {origin:"max"});  chart.addAxis("y", {vertical: true, leftBottom: true, min: 5000, max: 8000,  majorTickStep: 500, minorTickStep: 100});  chart.addPlot("plot1", {type: "Areas", hAxis:"x", vAxis:"y"});  chart.addPlot( "plot2", {type: "Grid", hAxis:"x", vAxis:"y"});  data1 = [{x:10,y:7200}, {x:20,y:6800}, {x:30,y:7000}, {x:40,y:6600}, {x:50,y:7000},  {x:60,y:6800}, {x:70,y:7200}, {x:80,y:6600}, {x:90,y:6800}, {x:100,y:7000}];  data2 = [{x:10,y:6800}, {x:20,y:5800}, {x:30,y:6400}, {x:40,y:5600}, {x:50,y:6000},  {x:60,y:6200}, {x:70,y:6600}, {x:80,y:7200}, {x:90,y:6300}, {x:100,y:6000}];  data3 = [{x:10,y:6000}, {x:20,y:6300}, {x:30,y:6800}, {x:40,y:6200}, {x:50,y:6200},  {x:60,y:6600}, {x:70,y:6300}, {x:80,y:6200}, {x:90,y:6000}, {x:100,y:5900}];  chart.addSeries("series B", data2, {plot: "plot1"});  chart.addSeries("series C", data3, {plot: "plot1"});  chart.addSeries("series A", data1, {plot: "plot1"});  chart.render();

运行结果如下:

图 8. 二维面积图示例

图 8 二维面积图示例

巧用折线图进行函数图像的绘制

我们可以使用折线图或者面积图完成函数图像的绘制,原理就是按照一定的步长循环将定义域中将 x,y 值计算出来组成一组数据添加的 Chart2D 对象中,下面这个例子就是使用了折线图绘制了正弦余弦曲线。

清单16绘制正弦余弦曲线

清单 16. 绘制正弦余弦曲线
 dojo.require("dojox.charting.Chart2D");  dojo.require("dojox.charting.themes.PlotKit.blue");  dojo.addOnLoad(function() {    var period = 2 * Math.PI;    var tick = Math.PI / 180.0;    var step = 5*Math.PI / 180.0;    var chart = new dojox.charting.Chart2D('chart_area');    chart.setTheme(dojox.charting.themes.PlotKit.blue);    chart.addAxis("x", {min: 0, max: period, majorTickStep: tick*30,                    minorTickStep: tick*10, minorLabels: false, font: '40px bold'});    chart.addAxis("y", {vertical: true, min: -1.01, max: 1, majorTickStep: 0.5,                    minorTickStep: 0.1, minorLabels: false, font: '40px bold'});    chart.addPlot("default", {type: 'Lines'});    chart.addPlot("grid", {type: "Grid", vMinorLines: true});    var series = {'sin' : [], 'cos' : []};    for(var i = 0; i < period; i+=step) {       series.sin.push({'x' : i, 'y' : Math.sin(i)});       series.cos.push({'x' : i, 'y' : Math.cos(i)});    }  chart.addSeries('sin', series.sin);  chart.addSeries('cos' , series.cos);  chart.render();  });

运行结果如下:

图 9. 正余弦曲线图示例

图 9. 正余弦曲线图示例

3D 柱状图的绘制

使用 Chart3D 与 Chart2D 略有不同,这主要是因为 3D 绘图比 2D 绘图要复杂一些,3D 绘图一个很重要的过程就是坐标变换,以及光照和渲染都是很重要的考虑要点。不过 Chart3D 已经对 gfx3D 进行了封装,我们只需要通过对简单的几个参数的设置就可以完成一个 3D 图表。我们可以从 清单 17中看出 Chart3D 对象的声明比 Chart2D 多了一些参数,这主要是两类,光照与摄像机。光照指的是 3D 物体的周围的光环境,其中 lights 是光源数组,也就是说 3D 物体可以接受多个光源的光照;ambient 为环境光,影响物体的各个立体面;specular 是镜面反射光,这是光源照射物体特定位置发生镜面反射所产生的高光。当然了,你甚至可以不用理解这些参数的意义,在实际使用中多次调整参数以满足自己的使用需求。

清单 17. 3D 绘图
 dojo.require("dojox.charting.Chart3D");  dojo.require("dojox.charting.plot3d.Bars");  dojo.require("dojox.charting.plot3d.Cylinders");  makeObjects = function(){  var m = dojox.gfx3d.matrix;  var chart = new dojox.charting.Chart3D("test",  {lights:   [{direction: {x: 5, y: 5, z: -5}, color: "white"}], 	 ambient:  {color:"white", intensi ty: 2}, 	 specular: "white"},  [m.cameraRotateXg(10), m.cameraRotateYg(-10), m.scale(0.8),  m.cameraTranslate(-50, -50, 0)]  );  var plot1 = new dojox.charting.plot3d.Bars(500, 500, {gap: 10, material: "yellow"});  plot1.setData([2,1,2,1,1,1,2,3,5]);  chart.addPlot(plot1);  var plot2 = new dojox.charting.plot3d.Bars(500, 500, {gap: 10, material: "red"});  plot2.setData([1,2,3,2,1,2,3,4,5]);  chart.addPlot(plot2);  var plot3 = new dojox.charting.plot3d.Cylinders (500, 500, {gap: 10, material: "#66F"});  plot3.setData([2,3,4,3,2,3,4,5,5]);  chart.addPlot(plot3);  var plot4 = new dojox.charting.plot3d.Cylinders (500, 500, {gap: 10, material: "#E6F"});  plot4.setData([3,4,5,4,3,4,5,5,5]);  chart.addPlot(plot4);  chart.generate().render();  };  dojo.addOnLoad(makeObjects);

运行这段代码,显示效果如下:

图 10. 三维柱状图示例

图 10. 三维柱状图示例

这个 3D 柱状图结合了长方体和圆柱体,dojox.charting.plot3d.Bars 是长方体的声明类,new dojox.charting.plot3d. Cylinders 是圆柱体的声明类。

DojoX Gfx 和 Gfx3D

DojoX Gfx 和 Gfx3D 是 DojoX 中进行绘图的两个包,分别提供了 2D 和 3D 的绘图 API。前面介绍的 DojoX Charting 就是在这两个包的基础上开发的。 Gfx 以及 Gfx 3D 是一组矢量绘图 API。对于原生的矢量图形,Gfx 能够支持 SVG、Canvas 和 VML,新版本中又增加了对 Silverlight 的支持。首先,我们来看看 DojoX Gfx 可以做什么。在 dojo 官方网站公布的开发包中有这么几个 Gfx 例子,见下图。可以看出,Gfx 对于简单的 2D 绘图已经绰绰有余了。

图 11.Gfx 绘图

图 11.Gfx 绘图

下面我们就来使用 Gfx 开始绘图。 Gfx 绘图的基本步骤可以简单的归为两步:打开一个画布(surface),然后“画”。在绘画之前,我们要例行公事,引入 dojox.gfx 包。然后通过 dojox.gfx 对象的 createSurface 方法建立画布。 Surface 提供了很多画笔来进行作画,这里我们介绍几个比较常用的。

  • 线性画笔:使用方法为 surface.createLine(opt),参数包含 x1、y1、x2、y2 四个属性,分别表示起点横纵坐标和终点横纵坐标;
  • 矩形画笔:使用方法为 surface.createRect(opt),参数 opt 是一个 JSON 对象,包括了属性 x、y、width、height,分别表示矩形左上角的横纵坐标以及举行的宽和高;
  • 圆形画笔:使用方法为 surface.createCircle(opt),参数 opt 具有三个属性,分别是圆心横坐标 cx、圆心纵坐标 cy、圆半径 r;
  • 路径画笔:这个是最强大的画笔,可以绘制任意曲线和图形,当然也是使用最复杂的画笔,使用方法为 surface.createPath(path),path 是描绘一组路径的字符串,描绘规则可以参考 SVG 中关于矢量路径的介绍。

除以上介绍的几种外还有点、折线、文字等画笔,并且还提供了组功能,可以使一组图形一起响应事件等。下面就看个简单的例子来加深理解。

清单 18. Gfx 绘图代码
 dojo.require("dojox.gfx");  surface = dojox.gfx.createSurface(dojo.byId("gfx_holder"), 700, 700);  surface.createRect({x: 260, y: 260, width: 50, height: 50}).setFill("#AAF");  surface.createLine({x1: 100, y1: 400, x2: 400, y2: 350}) 	 .setStroke({color:"#9F3",width:5});  surface.createCircle({cx: 200, cy: 200, r: 50}) 	 .setFill("#F EF").setStroke({color: "#F9A", width: 3});  var path="M153 334 " + 		"C153 334 151 334 151 334 C151 339 153 344 156 344 " + 		"C164 344 171 339 171 334 C171 322 164 314 156 314 " + 		"C142 314 131 322 131 334 C131 350 142 364 156 364 " + 		"C175 364 191 350 191 334 C191 311 175 294 156 294 " + 		"C131 294 111 311 111 334 C111 361 131 384 156 384 " + 		"C186 384 211 361 211 334 C211 300 186 274 156 274" surface.createPath(path).setFill("rgb(FF,FF,FF)").setStroke({color:"red",width:3});

清单 18中的代码将在 ID 为 gfx_holder 的 html 标记内添加这个绘图。这段代码中的 setFill 方法和 setStroke 方法分别用来设置填充效果和笔触效果。代码运行结果如下图所示。

图 12. Gfx 简单绘图示例

图 12. Gfx 简单绘图示例

Gfx3D 的工作原理是采用计算机图形学的原理将三维空间中的物体按照透视规则从三维坐标系转换成二维的坐标系然后通过 SVG 等矢量图显示出来。限于浏览器和 javascript 的性能,目前 Gfx3D 仅能绘制较为简单的 3D 物体和空间曲线,还不能绘制复杂的空间曲面以及进行纹理等渲染工作,但是 Gfx3D 足以满足大部分 Web 应用的需要了。 Gfx3D 的使用大致分三个步骤:建立画布,在画布上建立视图,在视图上建立 3D 物体。视图上必不可少的要设置光源以及摄像机方位。设置光源可以通过 setLights 方法来设定,摄像机方位则需要使用 dojox.gf3d.maxtrix 对象的 cameraRotateX、cameraRotateY、cameraRotateZ、cameraTranslate 等方法来确定。清单 19在画布上绘制了一个立方体和一个圆柱体。

清单 19. Gfx 3D 绘图
 dojo.require("dojox.gfx3d");  makeObjects = function(){  var surface = dojox.gfx.createSurface("test", 500, 500);  var view = surface.createViewport();  // 建立视图 view.setLights([{direction: {x: 0, y: 0, z: -10}, color: "white"}, 			 {direction: {x: 10, y: 0, z: -10}, color: "#444"}],  {color: "white", intensity: 2}, "white");  var m = dojox.gfx3d.matrix;  // 建立空间 var l = view.createCube({bottom: {x: 0, y: 0, z: 0}, top: {x: 100, y: 100, z: 100}}) 		 .setFill({type: "plastic", finish: "dull", color: "lime"});  // 绘制立方体 view.createCylinder({})   // 绘制圆柱体    .setTransform([m.translate(200, 100,200), m.rotateZg(60), m.rotateXg(-60)]) 	 .setStroke("black") 	 .setFill({type: "plastic", finish: "glossy", color: "red"});  var camera = [m.cameraRotateXg(20), m.cameraRotateYg(20),  m.cameraTranslate(-200, -200, 0)]; // 设置摄像机方位 view.applyCameraTransform(camera);  view.render();  };  dojo.addOnLoad(makeObjects);

运行,结果如下图所示。

图 13. Gfx-3D 简单绘图示例

图 13. Gfx-3D 简单绘图示例

其他 DojoX Widget

DojoX 的 widget 包中还提供了更多的小部件,非常的方便易用,本文的最后再来两个餐后甜点,拾色器和鱼眼。拾色器是我们经常会用到的小部件,用 DojoX 生成拾色器非常简单,仅需要 清单 20这一小段代码即可。

清单 20. 拾色器
 

除了这段 javascript 代码,为了能正确的显示拾色器的样式,我们还需要导入它的 css 文件:dojox/widget/ColorPicker/ColorPicker.css。代码中,属性 animatePoint 来确定指针是否有滑动动画,默认为 true;属性 showHsv 表示是否显示 HSV 颜色模式数值;属性 showRgb 表示是否显示 RGB 颜色模式的数值;webSafe 表示是否显示 Web 安全色。清单 20显示效果如下:

图 14 .DojoX 拾色器

图 14 .DojoX 拾色器

鱼眼的实现也很简单,我们需要制作一组图标,命名为 fe1.gif、fe2.gif、fe3.gif 一直到 fe7.gif。我们将它们和页面放在同一文件夹下。然后在网页中书写如 清单 21所示代码。

清单 21. 鱼眼
 

运行,鼠标移上去来看看效果。

图 15.DojoX 鱼眼

图 15 DojoX 鱼眼

结束语

JavaScript 并不是万能的,同样,使用 JavaScript 开发的 Dojo 也不是万能的,但是为了满足众多开发者的需要,DojoX 提供了非常丰富的选择,并且提供了对 Flash、SilverLight、Google Gear 等组件的支持,使得 Dojo 爱好者们可以开发出更好更强大的 Web 应用。随着 DojoX 项目的不断完善和成熟,Dojo 将给开发者们带来更多的惊喜。

参考资料

学习

  • http://dojotoolkit.org,dojo 官方站点,关于 dojo 最权威的站点。
  • http://dojocampus.org, Dojo 在线课程和教程。
  • 学习 本系列其他部分的内容,了解更多 Dojo 的实用技术。
  • http://www.openajax.org/index.php, 了解更多 Ajax 技术。
  • http://www.ibm.com/developerworks/cn/ajax/, Ajax 资源中心:developerWorks 上所有有关 Ajax 的问题都可以在这里找到解答。
  • “基于 Dojo 的本地化开发”(developerWorks,2008 年 1 月):本文介绍了基于 Dojo 的本地化的实现,通过实例讲解了如何利用 Dojo 提供的本地化支持模块来实现软件的本地化。
  • “提高基于 Dojo 的 Web 2.0 应用程序的性能”(developerWorks,2008 年 2 月):本文通过演示一些实用的技巧来提高 Dojo 的性能,帮助开发人员找出 Web 2.0 应用程序的性能瓶颈。
  • “使用 Dojo 开发支持 Accessibility 的 Web 应用”(developerWorks,2008 年 5 月):帮助开发人员了解 Accessibility 的基本内容,掌握 Dojo 开发可访问性 Web 应用的基本技能。
  • “使用 Dojo 国际化 Web 应用程序”(developerWorks,2008 年 8 月):通过本文获得有关如何使用 Dojo 这个重要特性的简短的指导。
  • wikipedia上关于 XMLHttpRequest 对象的详细介绍。
  • JSON 的官方网站,在这里可以找到最实用的关于 JSON 的第一手资料。
  • Wikipedia 上关于 REST 架构风格的介绍。
  • developerWorks 技术活动和 网络广播:随时关注 developerWorks 技术活动和网络广播。
  • developerWorks Web development 专区:通过专门关于 Web 技术的文章和教程,扩展您在网站开发方面的技能。

获得产品和技术

  • 下载最新版 Dojo 工具包。

讨论

  • 访问 Dojo 发起人 Alex Russell 的博客:有很多有深度的文章。

Dojo 作为最著名的 Ajax 开源项目之一,不仅让 Web 程序员可以免费获得和使用其框架进行 Web 应用的开发,更吸引了大量的开发者对其不断的扩充,开发新的组件。 DojoX was born in such a development community. DojoX is a collection of dojo-based open source projects, these open source projects have very good ideas and high practicality. These DojoX projects may grow into a stable version and remain in DojoX, and some may be migrated to Dojo Core or Dijit. This article will give a general overview of the projects in DojoX and introduce some of the more distinctive projects with examples. This article will mainly introduce DataGrid, Charting, Gfx/Gfx 3D and DojoX Widget.

认识 DojoX

目前 DojoX 项目主要扩展了数据结构与算法、数据处理与通信、实用工具、图形 API 以及 Web UI 等。

涉及到数据结构与算法的项目包括了 DojoX Collections、DojoX Encoding 等。 Collections defines many very useful data collections, including ArrayList, BinaryTree, Dictionary, Iterator, Queue, SortedList, Stack. The use of these sets will greatly improve the efficiency of program development and the quality of the program. Encoding not only provides string and character encoding conversion, but also provides symmetric algorithm Blowfish and MD5 digital digest algorithm.

DojoX Data、Embed、I/O、JSON、XML、RPC 等扩展了 Dojo 的数据处理与通信能力。 Among them, the Data project provides support for more data formats, including support for csv files and APIs provided by Google, Picasa, and so on.

DojoX 的图形 API 扩展了 Dojo 的动画效果,并提供了 2D、3D 绘图的支持。 DojoX Fx provides a variety of animation effects through extensions to dojo core and dojo fx; gfx provides a series of vector drawing methods; and gfx3d provides some simple 3D drawing APIs.

而更加丰富的 Web UI 以及 Web 小部件也是 DojoX 的一大亮点。 The powerful Grid, practical Charting, DojoX Image and DojoX Layout make the Web UI developed based on dojo richer. DojoX Widgets also provides richer widgets to meet the needs of most application development.

除以上介绍的项目外,DojoX 还收集了很多实用工具,读者可以在 dojo API 网站上获得更多的信息。 http://api.dojotoolkit.org/

接下来我们就来体验一下 DojoX 给我们带来的精彩吧

注意:本教程使用的 dojo 版本为 1.2.1,由于 1.2.x 版本里 dojo 以及 dojoX 的部分组件有较大变化,因此本文仅适用于 dojo1.2.x,对于 dojo1.0 的开发者本文仅供参考,部分代码不能正确运行

DojoX DataGrid

Grid 可能是 DojoX 中最受欢迎的部件,比起普通的 Web 表格部件,Grid 更像一个基于 Web 的 Excel 组件。 This allows Grid to cope with more complex data display and data manipulation. In dojox1.2, the DataGrid class is added to the dojox.grid package. This class is an enhancement and replacement of the original Grid class. It is called DataGrid because it is seamlessly integrated with the dojo data manipulation class store. . The previous Grid needs to package the store object as a model object before it can be used. If there is no special statement below, all Gird or DataGrid refers to the new version of DataGrid, not Grid1.0.

图 1 .DojoX DataGrid

图 1 .DojoX DataGrid

我们为什么需要 Grid 呢?下面列出了 Grid 的特性:

  • 用户只需向下拖动滚动条,Grid 即可加载延迟的记录,省去了翻页操作,减少 Web 与服务器交互,提高了性能;
  • 可以任意的增加和删除单元格、行、或者列;
  • 对行进行统计摘要,Grid 可以生成类似于 OLAP 分析的报表;
  • Grid 超越了二维表格的功能,它可以跨行或跨列合并单元格以满足不同的数据填充的需求;
  • 行列冻结功能,使得浏览数据更加灵活方便;
  • Grid 事件采用了钩子机制,我们可以通过 onStyle 钩子完成对样式的更改;
  • 单元格具备富操作,所有的 dijit 部件都可以在单元格中使用,并且单元格可以通过单击转换为编辑状态;
  • 可以为不同的单元格设置不同的上下文菜单;
  • Grid 嵌套,也就是说 Grid 可以在单元格中嵌套其他的 Grid,从而组成更为复杂的应用;

除此之外,Grid 还有具有其他很多特性,例如,非常实用的偶数行上色、灵活的选取功能、自动调整列宽、数据的展开 / 合闭等。

DataGrid 基础

要创建一个 DojoX DataGrid,就需要对 DataGrid 的基本工作过程有一个大致的了解。 The composition structure of a DataGrid instance is shown in the following figure. DojoX DataGrid is the basis of using DataGrid, so when using Grid, you need to load related dojox packages; a widget usually consists of a frame and style, so we need to specify the style of DataGrid Table and declare the DataGrid instance. The DataGrid instance will combine a Structure and a Store. Structure is the definition of a header and data model, and Store is used to carry data.

图 2 .DataGrid 组成结构

图 2 .DataGrid 组成结构

下面开始我们的第一个 DataGrid 应用为了在 Web 页面上创建一个 DataGrid 小部件,我们从最基本的二维表格开始。 First, we need to load some styles to ensure that the DataGrid can display normally, as shown in Listing 1.

清单 1. 加载样式
 

此处的 css 文件路径为相对于测试页面的相对路径。

在开始创建 Grid 之前,我们还要引入 Dojo 的基础包 dojo.js,以用来加载其他需要的 dojo 类,并加载 dojo.data.ItemFileReadStore 类以及 dojox.grid.DataGrid 类。 Next we can proceed to develop the first DataGrid.首先是布局的定义,如 清单 2

清单 2. 定义布局
 var layout = [ 		 {field: 'pro_no', name: 'Product Number' }, 		 {field: 'pro', name: 'Product' }, 		 {field: 'min_amount', name: 'Minimum Amount' }, 		 {field: 'max_amount', name: 'Maximum Amount' }, 		 {field: 'avg_amount', name: 'Average Amount' }  ];

这里定义了一个数组 layout,其中每一个成员表示一个列的定义,其中 field 指定了使用的数据项,该取值需要遵循 javascript 变量定义规则;name 为该列显示的名称。接下来是 store 的开发,代码如 清单 3

清单 3. 开发 store
 var sampleData = {  identifier: 'pro_no',  label: 'pro_no',  items: [  {pro_no:'2100', pro:'A Series', min_amount:346, max_amount:931, avg_amount:647},  {pro_no:'2200', pro:'B Series', min_amount:301, max_amount:894, avg_amount:608},  {pro_no:'2300', pro:'C Series', min_amount:456, max_amount:791, avg_amount:532},  {pro_no:'2400', pro:'D Series', min_amount:859, max_amount:2433, avg_amount:1840},  {pro_no:'2500', pro:'E Series', min_amount:459, max_amount:1433, avg_amount:1040}  ]  };  var jsonStore = new dojo.data.ItemFileReadStore({ data: sampleData });

在这里,我们首先定义一个 JSON 数据 sampleData,这里 identifier 是对于整行的唯一标识,因此在数据中不能出现重复;数组 items 是这个表格所显示的数据,其中数据必须完全符合 JSON 的语法,字符串两端必须使用引号,否则会出现语法错误,保险的办法是所有的值均用引号括住。

接下来,我们就要在网页的 Body 元素中定义 DataGrid 实例了,如 清单 4

清单 4. 定义 DataGrid 实例
 

dojoType 指定了该 Web 部件为 dojox.grid.DataGrid,数据使用 jsonStore,结构为 layout,自动调整宽度。到此,第一个 Grid 就已开发完毕,完整代码如 清单 5

清单 5. 完整代码
     first Grid              
First Grid

在浏览器中运行,效果如下:

图 3. 第一个 Grid 运行结果

图 3. 第一个 Grid 运行结果

DataGrid 开发详解

DataGrid 的创建

在 DataGrid 的开发中,有三种方法创建 DataGrid 实例,第一种是 javascript 创建结构,html 代码创建实例,我们第一个例子就是使用这种方式实现的;

第二种是由 html 代码创建结构及实例,在这种方法中,我们使用 table 标签,定义 Grid 的结构,而省去了在 javascript 中定义 structure 的部分。具体定义方式与标准的 html 书写方式非常类似,定义方式如 清单 6

清单 6. 由 html 代码创建结构及实例
 
Product Number Product Minimum Amount Maximu m Amount Average Amount

第三种方式就是采用纯 javascript 的方式定义 DataGrid 实例,清单 7声明网页加载完成后就在 id 为 gridNode 的页面结点上创建一个 DataGrid 实例。

清单 7. 纯 javascript 的方式定义 DataGrid 实例
 dojo.addOnLoad(function(){  // 指定页面加载完毕后执行 var grid = new dojox.grid.DataGrid({ 	 query: { pro_no: '*' }, 	 id: 'grid2', 	 store: jsonStore, 	 structure: [ 		 {field: 'pro_no', name: 'Product Number' }, 		 {field: 'pro', name: 'Product' }, 		 {field: 'min_amount', name: 'Minimum Amount' }, 		 {field: 'max_amount', na me: 'Maximum Amount' }, 		 {field: 'avg_amount', name: 'Average Amount' }  ],rowsPerPage: 20  	 }, 'gridNode');  // 设置 grid 显示在 id 为 gridNode 的节点下 grid.startup();  // 启动 grid  });

Grid1.2 可以通过这种方式很方便的与 dojo 容器结合在一起,动态创建页面布局。

Structure 详解

DataGrid 不仅可以创建简单的二维表格,还可以通过对 structure 的设计创建复杂的表格应用,同时还可以为每一列进行格式化或是取值。 We simply modify First Grid to get the code in Listing 8.

清单 8. 修改 First Grid
 function formatAmount(value){ 	 return '$ ' + value;  }  function getRange(rowIndex, item){ 	 if(!item){return '--';} 	 var grid = dijit.byId('grid'); 	 var max = grid.store.getValue(item, "max_amount"); 	 var min = grid.store.getValue(item, "min_amount"); 	 return max - min;  }  var subrow1 = [  {field: 'pro_no', name: 'Product Numb er', rowSpan: 2 },  {field: 'pro', name: 'Product', rowSpan: 2 },  {field: 'min_amount', name: 'Min. Amount',formatter: formatAmount,width: '80px' },  {field: 'avg_amount', name: 'Average Amount',formatter: formatAmount, rowSpan: 2 },  {field: 'range', name: 'Range',get:getRange, rowSpan: 2 }  ];  var subrow2 = [ 	 {field: 'max_amount', name: 'Max. Amount',formatter: formatAmount},  ];  var layout = [subrow1,subrow2];

这里,我们从新定义了 layout,将 layout 分为两个子行,其中子行 1 包含了五个字段,其中 pro_no、pro、avg_amount、range 具有值为 2 的 rowSpan 属性,也就表明这三列跨越了两行。 The second line has only one field max_amount. At the same time, we specified the formatter function for the three amount fields, adding a dollar sign in front of their values. The get method is specified for the range field to automatically obtain the difference between the maximum value and the minimum value.

显示效果如下:

图 4. DataGrid 布局示例 1

图 4. DataGrid 布局示例 1

除了 rowSpan 属性外我们还可以使用 colSpan 属性,这两个属性的用法与 html 中的用法一致,并且可以在 html 定义表结构中使用,我们再看这个表头的例子来理解一下 colSpan 的用法。

清单 9. colSpan 的应用
 var structure = [[ 	 {field: 'type', name: 'Type', rowSpan: 2}, 	 {field: 'pro', name: 'Product', rowSpan: 2}, 	 {field: 'Q20071', name: 'Q1',formatter: formatAmount }, 	 {field: 'Q20072', name: 'Q2',formatter: formatAmount }, 	 {field: 'Q20073', name: 'Q3',formatter: formatAmount }, 	 {field: 'Q20074', name: 'Q4',formatter: formatAmou nt }   ],[ 	 {field: 'Y2007', name: 'Year 2007',formatter: formatAmount, colSpan: 4 }  ]];

清单 9的显示效果如下:

图 5. DataGrid 布局示例 2

图 5 . DataGrid 布局示例 2

Store 的使用

DataGrid 使用了 Store 作为数据源,在以上的例子中,我们都是将数据写在 javascript 中然后作为 data 参数值传给 Store 的构造方法。 But in most cases, the data is dynamically obtained from the server through Ajax requests, which can also be achieved through the Store. We only need to pass in the requested url address when declaring the Store object, such as: new dojo.data.ItemFileReadStore({url:'jsondata.txt' }). Store includes two classes, dojo.data.ItemFileReadStore and dojo.data.ItemFileWriteStore. When we use the editing function of the DataGrid, we need to use ItemFileWriteStore as the data source. The following demonstrates a multi-functional DataGrid. This Grid uses an external data source to edit cells and pop-up a column selection menu by right-clicking on the header of the table. In order for the page to be correct, Listing 10 loads the required CSS.

清单 10. 加载所需 CSS
 

清单 11的代码引入了所需的 dojo 包,并创建了可编辑的 DataGrid,将其添加到了 id 为 gridNode 的页面节点中。 In order to make the column editable, you only need to add an editable attribute with a value of true to the JSON definition of the column in the structure definition.

清单 11. 引入所需 Dojo 包
   

清单 12定义了菜单 gridMenu 以及承载 DataGrid 的 DIV。

清单 12. 定义菜单
   
Data Grid

本例使用了外部数据源 dataGrid.txt,该文件的内容类似于 清单 13

清单 13. dataGrid.txt
 { 	 identifier: 'emp_no', 	 label: 'emp_no', 	 items: [      {emp_no:'2100', name:'Matt', gender:'M', dept_no:730, bonus:647}, 	 {emp_no:' 2200', name:'Lisa', gender:'F', dept_no:731, bonus:608}, 	 {emp_no:'2300', name:'Mick', gender:'M', dept_no:732, bonus:532}, 	 {emp_no:'2400', name:'John', gender:'M', dept_no:733, bonus:1840}, 	 {emp_no:'2500', name:'Jan', gender:'M', dept_no:734, bonus:1040}, 	 {emp_no:'2101', name:'Jeff', gender:'M', dept_no:730, bonus:647}, 	 {emp_no:'2202', name:'Frank', gender:'M', dept_no:731, bonus:608}, 	 {emp_no:'2303', name:'Fred', gender:'M', dept_no:732, bonus:532}  ]}

运行,结果如下图所示。

图 6. 可编辑的 DataGrid

图 6. 可编辑的 DataGrid

DojoX Charting

Charting 是基于 DojoX 绘图包的数据可视化组件,包括了 Chart2D 和 Chart3D 来分别绘制 2D 和 3D 的图表。 Chart2D 提供多种样式的饼图、柱状图、折线图、面积图、网格等图表。 Chart3D 目前仅提供了 3D 柱状图和 3D 圆柱图,并且从社区获取的信息表明由于 IE 上的性能问题导致 Chart3D 的开发暂时搁置。 Charting 的应用主要分为如下几个步骤:

  1. 首先引入所需要的 dojox 类,如:
    dojo.require("dojox.charting.Chart2D"); //Chart2D 所需要的 2D 类 
    dojo.require("dojox.charting.Chart3D"); //Chart3D 所需要的 3D 类 
    dojo.require("dojox.charting.themes.PlotKit.blue"); // 样式主题
  2. 第二,声明 Chart 对象,包括了 Chart2D 或 Char3D,
    如:var chart1=new dojox.charting.Charting.Chart2D('chart1');
    这里传入的参数为要在页面中载入 chart1 的元素的 ID,也就是 chart1 显示后的上层标签的 ID;
  3. 使用 Chart 对象的 setTheme 为 Chart 对象设置主题,来保证准确的绘制图表;< /li>
  4. 使用 Chart 对象的 addPlot 方法为 Chart 对象添加部件,可以添加多个部件;
  5. 使用 Chart 对象的 addSeries 方法为 Chart 对象添加数据;
  6. 最后,调用 render 方法将 chart 对象添加到页面节点中;

下面我们来看几个应用实例。

2D 饼图

清单 14的代码为 2D 饼图,我们可以看到该实例加载了类 Chart2D 和 themes.PlotKit.blue 对象。 chart1 对象声明在 ID 为 char1 的元素下,并被添加了一个 Pie 部件作为默认部件,数据为 3、2、5、1、6、4。

清单 14.2D 饼图
  …… 

运行结果如下:

图 7. 二维饼图示例

图 7. 二维饼图示例

带网格的 2D 面积图

这个例子中我们为 Chart2D 对象添加了两个部件,网格和面积图,如 清单 15。值得注意的是,我们为 chart 添加了两个部件,Plot1 和 Plot2,其中 Plot1 的类型为 Areas,Plot2 的类型为 Grid,我们给 Plot1 添加了三组数据,并没有给 Plot2 添加数据。

清单 15. 网格和面积图
 chart = new dojox.charting.Chart2D("chart2");  chart.setTheme(dojox.charting.themes.PlotKit.orange);  chart.addAxis("x", {origin:"max"});  chart.addAxis("y", {vertical: true, leftBottom: true, min: 5000, max: 8000,  majorTickStep: 500, minorTickStep: 100});  chart.addPlot("plot1", {type: "Areas", hAxis:"x", vAxis:"y"});  chart.addPlot("pl ot2", {type: "Grid", hAxis:"x", vAxis:"y"});  data1 = [{x:10,y:7200}, {x:20,y:6800}, {x:30,y:7000}, {x:40,y:6600}, {x:50,y:7000},  {x:60,y:6800}, {x:70,y:7200}, {x:80,y:6600}, {x:90,y:6800}, {x:100,y:7000}];  data2 = [{x:10,y:6800}, {x:20,y:5800}, {x:30,y:6400}, {x:40,y:5600}, {x:50,y:6000},  {x:60,y:6200}, {x:70,y:6600}, {x:80,y:7200}, {x:90,y:6300}, {x:100,y:6000}];  data3 = [{x:10,y:6000}, {x:20,y:6300}, {x:30,y:6800}, {x:40,y:6200}, {x:50,y:6200},  {x:60,y:6600}, {x:70,y:6300}, {x:80,y:6200}, {x:90,y:6000}, {x:100,y:5900}];  chart.addSeries("series B", data2, {plot: "plot1"});  chart.addSeries("series C", data3, {plot: "plot1"});  chart.addSeries("series A", data1, {plot: "plot1"});  chart.render();

运行结果如下:

图 8. 二维面积图示例

图 8 二维面积图示例

巧用折线图进行函数图像的绘制

我们可以使用折线图或者面积图完成函数图像的绘制,原理就是按照一定的步长循环将定义域中将 x,y 值计算出来组成一组数据添加的 Chart2D 对象中,下面这个例子就是使用了折线图绘制了正弦余弦曲线。

清单16绘制正弦余弦曲线

清单 16. 绘制正弦余弦曲线
 do jo.require("dojox.charting.Chart2D");  dojo.require("dojox.charting.themes.PlotKit.blue");  dojo.addOnLoad(function() {    var period = 2 * Math.PI;    var tick = Math.PI / 180.0;    var step = 5*Math.PI / 180.0;    var chart = new dojox.charting.Chart2D('chart_area');    chart.setTheme(dojox.charting.themes.PlotKit.blue);    chart.addAxis("x", {min: 0, max: period, majorTickStep: tick*30,                    minorTickStep: tick*10, minorLabels: false, font: '40px bold'});    chart.addAxis("y", {vertical: true, min: -1.01, max: 1, majorTickStep: 0.5,                    minorTickStep: 0.1, minorLabels: false, font: '40px bold'});    chart.addPlot("default", {type: 'Lines'});    chart.addPlot("grid", {type: "Grid", vMinorLines: true});    var series = {'sin' : [], 'cos' : []};    for(var i = 0; i < period; i+=step) {       series.sin.push({'x' : i, 'y' : Math.sin(i)});       series.cos.push({'x' : i, 'y' : Math.cos(i)});    }  chart.addSeries('sin', series.sin);  chart.addSeries('cos', se ries.cos);  chart.render();  });

运行结果如下:

图 9. 正余弦曲线图示例

图 9. 正余弦曲线图示例

3D 柱状图的绘制

使用 Chart3D 与 Chart2D 略有不同,这主要是因为 3D 绘图比 2D 绘图要复杂一些,3D 绘图一个很重要的过程就是坐标变换,以及光照和渲染都是很重要的考虑要点。不过 Chart3D 已经对 gfx3D 进行了封装,我们只需要通过对简单的几个参数的设置就可以完成一个 3D 图表。我们可以从 清单 17中看出 Chart3D 对象的声明比 Chart2D 多了一些参数,这主要是两类,光照与摄像机。光照指的是 3D 物体的周围的光环境,其中 lights 是光源数组,也就是说 3D 物体可以接受多个光源的光照;ambient 为环境光,影响物体的各个立体面;specular 是镜面反射光,这是光源照射物体特定位置发生镜面反射所产生的高光。当然了,你甚至可以不用理解这些参数的意义,在实际使用中多次调整参数以满足自己的使用需求。

清单 17. 3D 绘图
 dojo.require("dojox.charting.Chart3D");  dojo.require("dojox.charting.plot3d.Bars");  dojo.require("dojox.charting.plot3d.Cylinders");  makeObjects = function(){  var m = dojox.gfx3d.matrix;  var chart = new dojox.charting.Chart3D("test",  {lights:   [{direction: {x: 5, y: 5, z: -5}, color: "white"}], 	 ambient:  {color:"white", intensity: 2}, 	 specular: "white"},  [m.cameraRotateXg(10), m.cameraRotateYg(-10), m.scale(0.8),  m.cameraTranslate(-50, -50, 0)]  );  var plot1 = new dojox.charting.plot3d.Bars(500, 500, {gap: 10, material: "yellow"});  plot1.setData([2,1,2,1,1,1,2,3,5]);  chart.addPlot(plot1);  var plot2 = new dojox.charting.plot3d.Bars(500, 500, {gap: 10, material: "red"});  plot2.setData([1,2,3,2,1,2,3,4,5]);  chart.addPlot(plot2);  var plot3 = new dojox.charting.plot3d.Cylinders (500, 500, {gap: 10, material: "#66F"});  plot3.setData([2,3,4,3,2,3,4,5,5]);  chart.addPlot(plot3);  var plot4 = new dojox.charting.plot3d.Cylinders (500, 500, {gap: 10, material: "#E6F"});  plot4.setData([3,4,5,4,3,4,5,5,5]);  chart.addPlot(plot4);  chart.generate().render();  };  dojo.addOnLoad(makeObjects);

运行这段代码,显示效果如下:

图 10. 三维柱状图示例

图 10. 三维柱状图示例

这个 3D 柱状图结合了长方体和圆柱体,dojox.charting.plot3d.Bars 是长方体的声明类,new dojox.charting.plot3d. Cylinders 是圆柱体的声明类。

DojoX Gfx 和 Gfx3D

DojoX Gfx 和 Gfx3D 是 DojoX 中进行绘图的两个包,分别提供了 2D 和 3D 的绘图 API。前面介绍的 DojoX Charting 就是在这两个包的基础上开发的。 Gfx 以及 Gfx 3D 是一组矢量绘图 API。对于原生的矢量图形,Gfx 能够支持 SVG、Canvas 和 VML,新版本中又增加了对 Silverlight 的支持。首先,我们来看看 DojoX Gfx 可以做什么。在 dojo 官方网站公布的开发包中有这么几个 Gfx 例子,见下图。可以看出,Gfx 对于简单的 2D 绘图已经绰绰有余了。

图 11.Gfx 绘图

图 11.Gfx 绘图

下面我们就来使用 Gfx 开始绘图。 Gfx 绘图的基本步骤可以简单的归为两步:打开一个画布(surface),然后“画”。在绘画之前,我们要例行公事,引入 dojox.gfx 包。然后通过 dojox.gfx 对象的 createSurface 方法建立画布。 Surface 提供了很多画笔来进行作画,这里我们介绍几个比较常用的。

  • 线性画笔:使用方法为 surface.createLine(opt),参数包含 x1、y1、x2、y2 四个属性,分别表示起点横纵坐标和终点横纵坐标;
  • 矩形画笔:使用方法为 surface.createRect(opt),参数 opt 是一个 JSON 对象,包括了属性 x、y、width、height,分别表示矩形左上角的横纵坐标以及举行的宽和高;
  • 圆形画笔:使用方法为 surface.createCircle(opt),参数 opt 具有三个属性,分别是圆心横坐标 cx、圆心纵坐标 cy、圆半径 r;
  • 路径画笔:这个是最强大的画笔,可以绘制任意曲线和图形,当然也是使用最复杂的画笔,使用方法为 surface.createPath(path),path 是描绘一组路径的字符串,描绘规则可以参考 SVG 中关于矢量路径的介绍。

除以上介绍的几种外还有点、折线、文字等画笔,并且还提供了组功能,可以使一组图形一起响应事件等。下面就看个简单的例子来加深理解。

清单 18. Gfx 绘图代码
 dojo.require("dojox.gfx");  surface = dojox.gfx.createSurface(dojo.byId("gfx_holder"), 700, 700);  surface.createRect({x: 260, y: 260, width: 50, height: 50}).setFill("#AAF");  surface.createLine({x1: 100, y1: 400, x2: 400, y2: 350}) 	 .setStroke({color:"#9F3",width:5});  surface.createCircle({cx: 200, cy: 200, r: 50}) 	 .setFill("#FEF" ).setStroke({color: "#F9A", width: 3});  var path="M153 334 " + 		"C153 334 151 334 151 334 C151 339 153 344 156 344 " + 		"C164 344 171 339 171 334 C171 322 164 314 156 314 " + 		"C142 314 131 322 131 334 C131 350 142 364 156 364 " + 		"C175 364 191 350 191 334 C191 311 175 294 156 294 " + 		"C131 294 111 311 111 334 C111 361 131 384 156 384 " + 		"C186 384 211 361 211 334 C211 300 186 274 156 274" surface.createPath(path).setFill("rgb(FF,FF,FF)").setStroke({color:"red",width:3});

清单 18中的代码将在 ID 为 gfx_holder 的 html 标记内添加这个绘图。这段代码中的 setFill 方法和 setStroke 方法分别用来设置填充效果和笔触效果。代码运行结果如下图所示。

图 12. Gfx 简单绘图示例

图 12. Gfx 简单绘图示例

Gfx3D 的工作原理是采用计算机图形学的原理将三维空间中的物体按照透视规则从三维坐标系转换成二维的坐标系然后通过 SVG 等矢量图显示出来。限于浏览器和 javascript 的性能,目前 Gfx3D 仅能绘制较为简单的 3D 物体和空间曲线,还不能绘制复杂的空间曲面以及进行纹理等渲染工作,但是 Gfx3D 足以满足大部分 Web 应用的需要了。 Gfx3D 的使用大致分三个步骤:建立画布,在画布上建立视图,在视图上建立 3D 物体。视图上必不可少的要设置光源以及摄像机方位。设置光源可以通过 setLights 方法来设定,摄像机方位则需要使用 dojox.gf3d.maxtrix 对象的 cameraRotateX、cameraRotateY、cameraRotateZ、cameraTranslate 等方法来确定。清单 19在画布上绘制了一个立方体和一个圆柱体。

清单 19. Gfx 3D 绘图
 dojo.require("dojox.gfx3d");  makeObjects = function(){  var surface = dojox.gfx.createSurface("test", 500, 500);  var view = surface.createViewport();  // 建立视图 view.setLights([{direction: {x: 0, y: 0, z: -10}, color: "white"}, 			 {direction: {x: 10, y: 0, z: -10}, color: "#444"}],  {color: "white", intensity: 2}, "white");  var m = d ojox.gfx3d.matrix;  // 建立空间 var l = view.createCube({bottom: {x: 0, y: 0, z: 0}, top: {x: 100, y: 100, z: 100}}) 		 .setFill({type: "plastic", finish: "dull", color: "lime"});  // 绘制立方体 view.createCylinder({})   // 绘制圆柱体    .setTransform([m.translate(200, 100,200), m.rotateZg(60), m.rotateXg(-60)]) 	 .setStroke("black") 	 .setFill({type: "plastic", finish: "glossy", color: "red"});  var camera = [m.cameraRotateXg(20), m.cameraRotateYg(20),  m.cameraTranslate(-200, -200, 0)]; // 设置摄像机方位 view.applyCameraTransform(camera);  view.render();  };  dojo.addOnLoad(makeObjects);

运行,结果如下图所示。

图 13. Gfx-3D 简单绘图示例

图 13. Gfx-3D 简单绘图示例

其他 DojoX Widget

DojoX 的 widget 包中还提供了更多的小部件,非常的方便易用,本文的最后再来两个餐后甜点,拾色器和鱼眼。拾色器是我们经常会用到的小部件,用 DojoX 生成拾色器非常简单,仅需要 清单 20这一小段代码即可。

清单 20. 拾色器
 

除了这段 javascript 代码,为了能正确的显示拾色器的样式,我们还需要导入它的 css 文件:dojox/widget/ColorPicker/ColorPicker.css。代码中,属性 animatePoint 来确定指针是否有滑动动画,默认为 true;属性 showHsv 表示是否显示 HSV 颜色模式数值;属性 showRgb 表示是否显示 RGB 颜色模式的数值;webSafe 表示是否显示 Web 安全色。清单 20显示效果如下:

图 14 .DojoX 拾色器

图 14 .DojoX 拾色器

鱼眼的实现也很简单,我们需要制作一组图标,命名为 fe1.gif、fe2.gif、fe3.gif 一直到 fe7.gif。我们将它们和页面放在同一文件夹下。然后在网页中书写如 清单 21所示代码。

清单 21. 鱼眼
 

运行,鼠标移上去来看看效果。

图 15.DojoX 鱼眼

图 15 DojoX 鱼眼

结束语

JavaScript 并不是万能的,同样,使用 JavaScript 开发的 Dojo 也不是万能的,但是为了满足众多开发者的需要,DojoX 提供了非常丰富的选择,并且提供了对 Flash、SilverLight、Google Gear 等组件的支持,使得 Dojo 爱好者们可以开发出更好更强大的 Web 应用。随着 DojoX 项目的不断完善和成熟,Dojo 将给开发者们带来更多的惊喜。

Dojo 作为最著名的 Ajax 开源项目之一,不仅让 Web 程序员可以免费获得和使用其框架进行 Web 应用的开发,更吸引了大量的开发者对其不断的扩充,开发新的组件。 DojoX was born in such a development community. DojoX is a collection of dojo-based open source projects, these open source projects have very good ideas and high practicality. These DojoX projects may grow into a stable version and remain in DojoX, and some may be migrated to Dojo Core or Dijit. This article will give a general overview of the projects in DojoX and introduce some of the more distinctive projects with examples. This article will mainly introduce DataGrid, Charting, Gfx/Gfx 3D and DojoX Widget.

认识 DojoX

目前 DojoX 项目主要扩展了数据结构与算法、数据处理与通信、实用工具、图形 API 以及 Web UI 等。

涉及到数据结构与算法的项目包括了 DojoX Collections、DojoX Encoding 等。 Collections defines many very useful data collections, including ArrayList, BinaryTree, Dictionary, Iterator, Queue, SortedList, Stack. The use of these sets will greatly improve the efficiency of program development and the quality of the program. Encoding not only provides string and character encoding conversion, but also provides symmetric algorithm Blowfish and MD5 digital digest algorithm.

DojoX Data、Embed、I/O、JSON、XML、RPC 等扩展了 Dojo 的数据处理与通信能力。 Among them, the Data project provides support for more data formats, including support for csv files and APIs provided by Google, Picasa, and so on.

DojoX 的图形 API 扩展了 Dojo 的动画效果,并提供了 2D、3D 绘图的支持。 DojoX Fx provides a variety of animation effects through extensions to dojo core and dojo fx; gfx provides a series of vector drawing methods; and gfx3d provides some simple 3D drawing APIs.

而更加丰富的 Web UI 以及 Web 小部件也是 DojoX 的一大亮点。 The powerful Grid, practical Charting, DojoX Image and DojoX Layout make the Web UI developed based on dojo richer. DojoX Widgets also provides richer widgets to meet the needs of most application development.

除以上介绍的项目外,DojoX 还收集了很多实用工具,读者可以在 dojo API 网站上获得更多的信息。 http://api.dojotoolkit.org/

接下来我们就来体验一下 DojoX 给我们带来的精彩吧

注意:本教程使用的 dojo 版本为 1.2.1,由于 1.2.x 版本里 dojo 以及 dojoX 的部分组件有较大变化,因此本文仅适用于 dojo1.2.x,对于 dojo1.0 的开发者本文仅供参考,部分代码不能正确运行

DojoX DataGrid

Grid 可能是 DojoX 中最受欢迎的部件,比起普通的 Web 表格部件,Grid 更像一个基于 Web 的 Excel 组件。 This allows Grid to cope with more complex data display and data manipulation. In dojox1.2, the DataGrid class is added to the dojox.grid package. This class is an enhancement and replacement of the original Grid class. It is called DataGrid because it is seamlessly integrated with the dojo data manipulation class store. . The previous Grid needs to package the store object as a model object before it can be used. If there is no special statement below, all Gird or DataGrid refers to the new version of DataGrid, not Grid1.0.

图 1 .DojoX DataGrid

图 1 .DojoX DataGrid

我们为什么需要 Grid 呢?下面列出了 Grid 的特性:

  • 用户只需向下拖动滚动条,Grid 即可加载延迟的记录,省去了翻页操作,减少 Web 与服务器交互,提高了性能;
  • 可以任意的增加和删除单元格、行、或者列;
  • 对行进行统计摘要,Grid 可以生成类似于 OLAP 分析的报表;
  • Grid 超越了二维表格的功能,它可以跨行或跨列合并单元格以满足不同的数据填充的需求;
  • 行列冻结功能,使得浏览数据更加灵活方便;
  • Grid 事件采用了钩子机制,我们可以通过 onStyle 钩子完成对样式的更改;
  • 单元格具备富操作,所有的 dijit 部件都可以在单元格中使用,并且单元格可以通过单击转换为编辑状态;
  • 可以为不同的单元格设置不同的上下文菜单;
  • Grid 嵌套,也就是说 Grid 可以在单元格中嵌套其他的 Grid,从而组成更为复杂的应用;

除此之外,Grid 还有具有其他很多特性,例如,非常实用的偶数行上色、灵活的选取功能、自动调整列宽、数据的展开 / 合闭等。

DataGrid 基础

要创建一个 DojoX DataGrid,就需要对 DataGrid 的基本工作过程有一个大致的了解。 The composition structure of a DataGrid instance is shown in the following figure. DojoX DataGrid is the basis of using DataGrid, so when using Grid, you need to load related dojox packages; a widget usually consists of a frame and style, so we need to specify the style of DataGrid Table and declare the DataGrid instance. The DataGrid instance will combine a Structure and a Store. Structure is the definition of a header and data model, and Store is used to carry data.

图 2 .DataGrid 组成结构

图 2 .DataGrid 组成结构

下面开始我们的第一个 DataGrid 应用为了在 Web 页面上创建一个 DataGrid 小部件,我们从最基本的二维表格开始。 First, we need to load some styles to ensure that the DataGrid can display normally, as shown in Listing 1.

清单 1. 加载样式
 

此处的 css 文件路径为相对于测试页面的相对路径。

在开始创建 Grid 之前,我们还要引入 Dojo 的基础包 dojo.js,以用来加载其他需要的 dojo 类,并加载 dojo.data.ItemFileReadStore 类以及 dojox.grid.DataGrid 类。 Next we can proceed to develop the first DataGrid.首先是布局的定义,如 清单 2

清单 2. 定义布局
 var layout = [ 		 {field: 'pro_no', name: 'Product Number' }, 		 {field: 'pro', name: 'Product' }, 		 {field: 'min_amount', name: 'Minimum Amount' }, 		 {field: 'max_amount', name: 'Maximum Amount' }, 		 {field: 'avg_amount', name: 'Average Amount' }  ];

这里定义了一个数组 layout,其中每一个成员表示一个列的定义,其中 field 指定了使用的数据项,该取值需要遵循 javascript 变量定义规则;name 为该列显示的名称。接下来是 store 的开发,代码如 清单 3

清单 3. 开发 store
 var sampleData = {  identifier: 'pro_no',  label: 'pro_no',  items: [  {pro_no:'2100', pro:'A Series', min_amount:346, max_amount:931, avg_amount:647},  {pro_no:'2200', pro:'B Series', min_amount:301, max_amount:894, avg_amount:608},  {pro_no:'2300', pro:'C Series', min_amount:456, max_amount:791, avg_amount:532},  {pr o_no:'2400', pro:'D Series', min_amount:859, max_amount:2433, avg_amount:1840},  {pro_no:'2500', pro:'E Series', min_amount:459, max_amount:1433, avg_amount:1040}  ]  };  var jsonStore = new dojo.data.ItemFileReadStore({ data: sampleData });

在这里,我们首先定义一个 JSON 数据 sampleData,这里 identifier 是对于整行的唯一标识,因此在数据中不能出现重复;数组 items 是这个表格所显示的数据,其中数据必须完全符合 JSON 的语法,字符串两端必须使用引号,否则会出现语法错误,保险的办法是所有的值均用引号括住。

接下来,我们就要在网页的 Body 元素中定义 DataGrid 实例了,如 清单 4

清单 4. 定义 DataGrid 实例
 

dojoType 指定了该 Web 部件为 dojox.grid.DataGrid,数据使用 jsonStore,结构为 layout,自动调整宽度。到此,第一个 Grid 就已开发完毕,完整代码如 清单 5

清单 5. 完整代码
     first Grid            
First Gr id

在浏览器中运行,效果如下:

图 3. 第一个 Grid 运行结果

图 3. 第一个 Grid 运行结果

DataGrid 开发详解

DataGrid 的创建

在 DataGrid 的开发中,有三种方法创建 DataGrid 实例,第一种是 javascript 创建结构,html 代码创建实例,我们第一个例子就是使用这种方式实现的;

第二种是由 html 代码创建结构及实例,在这种方法中,我们使用 table 标签,定义 Grid 的结构,而省去了在 javascript 中定义 structure 的部分。具体定义方式与标准的 html 书写方式非常类似,定义方式如 清单 6

清单 6. 由 html 代码创建结构及实例
 
Product Number Product Minimum Amount Maximum A mount Average Amount

第三种方式就是采用纯 javascript 的方式定义 DataGrid 实例,清单 7声明网页加载完成后就在 id 为 gridNode 的页面结点上创建一个 DataGrid 实例。

清单 7. 纯 javascript 的方式定义 DataGrid 实例
 dojo.addOnLoad(function(){  // 指定页面加载完毕后执行 var grid = new dojox.grid.DataGrid({ 	 query: { pro_no: '*' }, 	 id: 'grid2', 	 store: jsonStore, 	 structure: [ 		 {field: 'pro_no', name: 'Product Number' }, 		 {field: 'pro', name: 'Product' }, 		 {field: 'min_amount', name: 'Minimum Amount' }, 		 {field: 'max_amount', name: 'Maximum Amount' }, 		 {field: 'avg_amount', name: 'Average Amount' }  ],rowsPerPage: 20  	 }, 'gridNode');  // 设置 grid 显示在 id 为 gridNode 的节点下 grid.startup();  // 启动 grid  });

Grid1.2 可以通过这种方式很方便的与 dojo 容器结合在一起,动态创建页面布局。

Structure 详解

DataGrid 不仅可以创建简单的二维表格,还可以通过对 structure 的设计创建复杂的表格应用,同时还可以为每一列进行格式化或是取值。 We simply modify First Grid to get the code in Listing 8.

清单 8. 修改 First Grid
 function formatAmount(value){ 	 return '$ ' + value;  }  function getRange(rowIndex, item){ 	 if(!item){return '--';} 	 var grid = dijit.byId('grid'); 	 var max = grid.store.getValue(item, "max_amount"); 	 var min = grid.store.getValue(item, "min_amount"); 	 return max - min;  }  var subrow1 = [  {field: 'pro_no', name: 'Product Number' , rowSpan: 2 },  {field: 'pro', name: 'Product', rowSpan: 2 },  {field: 'min_amount', name: 'Min. Amount',formatter: formatAmount,width: '80px' },  {field: 'avg_amount', name: 'Average Amount',formatter: formatAmount, rowSpan: 2 },  {field: 'range', name: 'Range',get:getRange, rowSpan: 2 }  ];  var subrow2 = [ 	 {field: 'max_amount', name: 'Max. Amount',formatter: formatAmount},  ];  var layout = [subrow1,subrow2];

这里,我们从新定义了 layout,将 layout 分为两个子行,其中子行 1 包含了五个字段,其中 pro_no、pro、avg_amount、range 具有值为 2 的 rowSpan 属性,也就表明这三列跨越了两行。 The second line has only one field max_amount. At the same time, we specified the formatter function for the three amount fields, adding a dollar sign in front of their values. The get method is specified for the range field to automatically obtain the difference between the maximum value and the minimum value.

显示效果如下:

图 4. DataGrid 布局示例 1

图 4. DataGrid 布局示例 1

除了 rowSpan 属性外我们还可以使用 colSpan 属性,这两个属性的用法与 html 中的用法一致,并且可以在 html 定义表结构中使用,我们再看这个表头的例子来理解一下 colSpan 的用法。

清单 9. colSpan 的应用
 var structure = [[ 	 {field: 'type', name: 'Type', rowSpan: 2}, 	 {field: 'pro', name: 'Product', rowSpan: 2}, 	 {field: 'Q20071', name: 'Q1',formatter: formatAmount }, 	 {field: 'Q20072', name: 'Q2',formatter: formatAmount }, 	 {field: 'Q20073', name: 'Q3',formatter: formatAmount }, 	 {field: 'Q20074', name: 'Q4',formatter: formatAmount }   ],[ 	 {field: 'Y2007', name: 'Year 2007',formatter: formatAmount, colSpan: 4 }  ]];

清单 9的显示效果如下:

图 5. DataGrid 布局示例 2

图 5 . DataGrid 布局示例 2

Store 的使用

DataGrid 使用了 Store 作为数据源,在以上的例子中,我们都是将数据写在 javascript 中然后作为 data 参数值传给 Store 的构造方法。 But in most cases, the data is dynamically obtained from the server through Ajax requests, which can also be achieved through the Store. We only need to pass in the requested url address when declaring the Store object, such as: new dojo.data.ItemFileReadStore({url:'jsondata.txt' }). Store includes two classes, dojo.data.ItemFileReadStore and dojo.data.ItemFileWriteStore. When we use the editing function of the DataGrid, we need to use ItemFileWriteStore as the data source. The following demonstrates a multi-functional DataGrid. This Grid uses an external data source to edit cells and pop-up a column selection menu by right-clicking on the header of the table. In order for the page to be correct, Listing 10 loads the required CSS.

清单 10. 加载所需 CSS
 

清单 11的代码引入了所需的 dojo 包,并创建了可编辑的 DataGrid,将其添加到了 id 为 gridNode 的页面节点中。 In order to make the column editable, you only need to add an editable attribute with a value of true to the JSON definition of the column in the structure definition.

清单 11. 引入所需 Dojo 包
   

清单 12定义了菜单 gridMenu 以及承载 DataGrid 的 DIV。

清单 12. 定义菜单
   
Data Grid

本例使用了外部数据源 dataGrid.txt,该文件的内容类似于 清单 13

清单 13. dataGrid.txt
 { 	 identifier: 'emp_no', 	 label: 'emp_no', 	 items: [      {emp_no:'2100', name:'Matt', gender:'M', dept_no:730, bonus:647}, 	 {emp_no:'2200', n ame:'Lisa', gender:'F', dept_no:731, bonus:608}, 	 {emp_no:'2300', name:'Mick', gender:'M', dept_no:732, bonus:532}, 	 {emp_no:'2400', name:'John', gender:'M', dept_no:733, bonus:1840}, 	 {emp_no:'2500', name:'Jan', gender:'M', dept_no:734, bonus:1040}, 	 {emp_no:'2101', name:'Jeff', gender:'M', dept_no:730, bonus:647}, 	 {emp_no:'2202', name:'Frank', gender:'M', dept_no:731, bonus:608}, 	 {emp_no:'2303', name:'Fred', gender:'M', dept_no:732, bonus:532}  ]}

运行,结果如下图所示。

图 6. 可编辑的 DataGrid

图 6. 可编辑的 DataGrid

DojoX Charting

Charting 是基于 DojoX 绘图包的数据可视化组件,包括了 Chart2D 和 Chart3D 来分别绘制 2D 和 3D 的图表。 Chart2D 提供多种样式的饼图、柱状图、折线图、面积图、网格等图表。 Chart3D 目前仅提供了 3D 柱状图和 3D 圆柱图,并且从社区获取的信息表明由于 IE 上的性能问题导致 Chart3D 的开发暂时搁置。 Charting 的应用主要分为如下几个步骤:

  1. 首先引入所需要的 dojox 类,如:
    dojo.require("dojox.charting.Chart2D"); //Chart2D 所需要的 2D 类 
    dojo.require("dojox.charting.Chart3D"); //Chart3D 所需要的 3D 类 
    dojo.require("dojox.charting.themes.PlotKit.blue"); // 样式主题
  2. 第二,声明 Chart 对象,包括了 Chart2D 或 Char3D,
    如:var chart1=new dojox.charting.Charting.Chart2D('chart1');
    这里传入的参数为要在页面中载入 chart1 的元素的 ID,也就是 chart1 显示后的上层标签的 ID;
  3. 使用 Chart 对象的 setTheme 为 Chart 对象设置主题,来保证准确的绘制图表;
  4. 使用 Chart 对象的 addPlot 方法为 Chart 对象添加部件,可以添加多个部件;
  5. 使用 Chart 对象的 addSeries 方法为 Chart 对象添加数据;
  6. 最后,调用 render 方法将 chart 对象添加到页面节点中;

下面我们来看几个应用实例。

2D 饼图

清单 14的代码为 2D 饼图,我们可以看到该实例加载了类 Chart2D 和 themes.PlotKit.blue 对象。 chart1 对象声明在 ID 为 char1 的元素下,并被添加了一个 Pie 部件作为默认部件,数据为 3、2、5、1、6、4。

清单 14.2D 饼图
  …… 

运行结果如下:

图 7. 二维饼图示例

图 7. 二维饼图示例

带网格的 2D 面积图

这个例子中我们为 Chart2D 对象添加了两个部件,网格和面积图,如 清单 15。值得注意的是,我们为 chart 添加了两个部件,Plot1 和 Plot2,其中 Plot1 的类型为 Areas,Plot2 的类型为 Grid,我们给 Plot1 添加了三组数据,并没有给 Plot2 添加数据。

清单 15. 网格和面积图
 chart = new dojox.charting.Chart2D("chart2");  chart.setTheme(dojox.charting.themes.PlotKit.orange);  chart.addAxis("x", {origin:"max"});  chart.addAxis("y", {vertical: true, leftBottom: true, min: 5000, max: 8000,  majorTickStep: 500, minorTickStep: 100});  chart.addPlot("plot1", {type: "Areas", hAxis:"x", vAxis:"y"});  chart.addPlot("plot2 ", {type: "Grid", hAxis:"x", vAxis:"y"});  data1 = [{x:10,y:7200}, {x:20,y:6800}, {x:30,y:7000}, {x:40,y:6600}, {x:50,y:7000},  {x:60,y:6800}, {x:70,y:7200}, {x:80,y:6600}, {x:90,y:6800}, {x:100,y:7000}];  data2 = [{x:10,y:6800}, {x:20,y:5800}, {x:30,y:6400}, {x:40,y:5600}, {x:50,y:6000},  {x:60,y:6200}, {x:70,y:6600}, {x:80,y:7200}, {x:90,y:6300}, {x:100,y:6000}];  data3 = [{x:10,y:6000}, {x:20,y:6300}, {x:30,y:6800}, {x:40,y:6200}, {x:50,y:6200},  {x:60,y:6600}, {x:70,y:6300}, {x:80,y:6200}, {x:90,y:6000}, {x:100,y:5900}];  chart.addSeries("series B", data2, {plot: "plot1"});  chart.addSeries("series C", data3, {plot: "plot1"});  chart.addSeries("series A", data1, {plot: "plot1"});  chart.render();

运行结果如下:

图 8. 二维面积图示例

图 8 二维面积图示例

巧用折线图进行函数图像的绘制

我们可以使用折线图或者面积图完成函数图像的绘制,原理就是按照一定的步长循环将定义域中将 x,y 值计算出来组成一组数据添加的 Chart2D 对象中,下面这个例子就是使用了折线图绘制了正弦余弦曲线。

清单16绘制正弦余弦曲线

清单 16. 绘制正弦余弦曲线
 dojo.r equire("dojox.charting.Chart2D");  dojo.require("dojox.charting.themes.PlotKit.blue");  dojo.addOnLoad(function() {    var period = 2 * Math.PI;    var tick = Math.PI / 180.0;    var step = 5*Math.PI / 180.0;    var chart = new dojox.charting.Chart2D('chart_area');    chart.setTheme(dojox.charting.themes.PlotKit.blue);    chart.addAxis("x", {min: 0, max: period, majorTickStep: tick*30,                    minorTickStep: tick*10, minorLabels: false, font: '40px bold'});    chart.addAxis("y", {vertical: true, min: -1.01, max: 1, majorTickStep: 0.5,                    minorTickStep: 0.1, minorLabels: false, font: '40px bold'});    chart.addPlot("default", {type: 'Lines'});    chart.addPlot("grid", {type: "Grid", vMinorLines: true});    var series = {'sin' : [], 'cos' : []};    for(var i = 0; i < period; i+=step) {       series.sin.push({'x' : i, 'y' : Math.sin(i)});       series.cos.push({'x' : i, 'y' : Math.cos(i)});    }  chart.addSeries('sin', series.sin);  chart.addSeries('cos', series .cos);  chart.render();  });

运行结果如下:

图 9. 正余弦曲线图示例

图 9. 正余弦曲线图示例

3D 柱状图的绘制

使用 Chart3D 与 Chart2D 略有不同,这主要是因为 3D 绘图比 2D 绘图要复杂一些,3D 绘图一个很重要的过程就是坐标变换,以及光照和渲染都是很重要的考虑要点。不过 Chart3D 已经对 gfx3D 进行了封装,我们只需要通过对简单的几个参数的设置就可以完成一个 3D 图表。我们可以从 清单 17中看出 Chart3D 对象的声明比 Chart2D 多了一些参数,这主要是两类,光照与摄像机。光照指的是 3D 物体的周围的光环境,其中 lights 是光源数组,也就是说 3D 物体可以接受多个光源的光照;ambient 为环境光,影响物体的各个立体面;specular 是镜面反射光,这是光源照射物体特定位置发生镜面反射所产生的高光。当然了,你甚至可以不用理解这些参数的意义,在实际使用中多次调整参数以满足自己的使用需求。

清单 17. 3D 绘图
 dojo.require("dojox.charting.Chart3D");  dojo.require("dojox.charting.plot3d.Bars");  dojo.require("dojox.charting.plot3d.Cylinders");  makeObjects = function(){  var m = dojox.gfx3d.matrix;  var chart = new dojox.charting.Chart3D("test",  {lights:   [{direction: {x: 5, y: 5, z: -5}, color: "white"}], 	 ambient:  {color:"white", intensity: 2} , 	 specular: "white"},  [m.cameraRotateXg(10), m.cameraRotateYg(-10), m.scale(0.8),  m.cameraTranslate(-50, -50, 0)]  );  var plot1 = new dojox.charting.plot3d.Bars(500, 500, {gap: 10, material: "yellow"});  plot1.setData([2,1,2,1,1,1,2,3,5]);  chart.addPlot(plot1);  var plot2 = new dojox.charting.plot3d.Bars(500, 500, {gap: 10, material: "red"});  plot2.setData([1,2,3,2,1,2,3,4,5]);  chart.addPlot(plot2);  var plot3 = new dojox.charting.plot3d.Cylinders (500, 500, {gap: 10, material: "#66F"});  plot3.setData([2,3,4,3,2,3,4,5,5]);  chart.addPlot(plot3);  var plot4 = new dojox.charting.plot3d.Cylinders (500, 500, {gap: 10, material: "#E6F"});  plot4.setData([3,4,5,4,3,4,5,5,5]);  chart.addPlot(plot4);  chart.generate().render();  };  dojo.addOnLoad(makeObjects);

运行这段代码,显示效果如下:

图 10. 三维柱状图示例

图 10. 三维柱状图示例

这个 3D 柱状图结合了长方体和圆柱体,dojox.charting.plot3d.Bars 是长方体的声明类,new dojox.charting.plot3d. Cylinders 是圆柱体的声明类。

DojoX Gfx 和 Gfx3D

DojoX Gfx 和 Gfx3D 是 DojoX 中进行绘图的两个包,分别提供了 2D 和 3D 的绘图 API。前面介绍的 DojoX Charting 就是在这两个包的基础上开发的。 Gfx 以及 Gfx 3D 是一组矢量绘图 API。对于原生的矢量图形,Gfx 能够支持 SVG、Canvas 和 VML,新版本中又增加了对 Silverlight 的支持。首先,我们来看看 DojoX Gfx 可以做什么。在 dojo 官方网站公布的开发包中有这么几个 Gfx 例子,见下图。可以看出,Gfx 对于简单的 2D 绘图已经绰绰有余了。

图 11.Gfx 绘图

图 11.Gfx 绘图

下面我们就来使用 Gfx 开始绘图。 Gfx 绘图的基本步骤可以简单的归为两步:打开一个画布(surface),然后“画”。在绘画之前,我们要例行公事,引入 dojox.gfx 包。然后通过 dojox.gfx 对象的 createSurface 方法建立画布。 Surface 提供了很多画笔来进行作画,这里我们介绍几个比较常用的。

  • 线性画笔:使用方法为 surface.createLine(opt),参数包含 x1、y1、x2、y2 四个属性,分别表示起点横纵坐标和终点横纵坐标;
  • 矩形画笔:使用方法为 surface.createRect(opt),参数 opt 是一个 JSON 对象,包括了属性 x、y、width、height,分别表示矩形左上角的横纵坐标以及举行的宽和高;
  • 圆形画笔:使用方法为 surface.createCircle(opt),参数 opt 具有三个属性,分别是圆心横坐标 cx、圆心纵坐标 cy、圆半径 r;
  • 路径画笔:这个是最强大的画笔,可以绘制任意曲线和图形,当然也是使用最复杂的画笔,使用方法为 surface.createPath(path),path 是描绘一组路径的字符串,描绘规则可以参考 SVG 中关于矢量路径的介绍。

除以上介绍的几种外还有点、折线、文字等画笔,并且还提供了组功能,可以使一组图形一起响应事件等。下面就看个简单的例子来加深理解。

清单 18. Gfx 绘图代码
 dojo.require("dojox.gfx");  surface = dojox.gfx.createSurface(dojo.byId("gfx_holder"), 700, 700);  surface.createRect({x: 260, y: 260, width: 50, height: 50}).setFill("#AAF");  surface.createLine({x1: 100, y1: 400, x2: 400, y2: 350}) 	 .setStroke({color:"#9F3",width:5});  surface.createCircle({cx: 200, cy: 200, r: 50}) 	 .setFill("#FEF").s etStroke({color: "#F9A", width: 3});  var path="M153 334 " + 		"C153 334 151 334 151 334 C151 339 153 344 156 344 " + 		"C164 344 171 339 171 334 C171 322 164 314 156 314 " + 		"C142 314 131 322 131 334 C131 350 142 364 156 364 " + 		"C175 364 191 350 191 334 C191 311 175 294 156 294 " + 		"C131 294 111 311 111 334 C111 361 131 384 156 384 " + 		"C186 384 211 361 211 334 C211 300 186 274 156 274" surface.createPath(path).setFill("rgb(FF,FF,FF)").setStroke({color:"red",width:3});

清单 18中的代码将在 ID 为 gfx_holder 的 html 标记内添加这个绘图。这段代码中的 setFill 方法和 setStroke 方法分别用来设置填充效果和笔触效果。代码运行结果如下图所示。

图 12. Gfx 简单绘图示例

图 12. Gfx 简单绘图示例

Gfx3D 的工作原理是采用计算机图形学的原理将三维空间中的物体按照透视规则从三维坐标系转换成二维的坐标系然后通过 SVG 等矢量图显示出来。限于浏览器和 javascript 的性能,目前 Gfx3D 仅能绘制较为简单的 3D 物体和空间曲线,还不能绘制复杂的空间曲面以及进行纹理等渲染工作,但是 Gfx3D 足以满足大部分 Web 应用的需要了。 Gfx3D 的使用大致分三个步骤:建立画布,在画布上建立视图,在视图上建立 3D 物体。视图上必不可少的要设置光源以及摄像机方位。设置光源可以通过 setLights 方法来设定,摄像机方位则需要使用 dojox.gf3d.maxtrix 对象的 cameraRotateX、cameraRotateY、cameraRotateZ、cameraTranslate 等方法来确定。清单 19在画布上绘制了一个立方体和一个圆柱体。

清单 19. Gfx 3D 绘图
 dojo.require("dojox.gfx3d");  makeObjects = function(){  var surface = dojox.gfx.createSurface("test", 500, 500);  var view = surface.createViewport();  // 建立视图 view.setLights([{direction: {x: 0, y: 0, z: -10}, color: "white"}, 			 {direction: {x: 10, y: 0, z: -10}, color: "#444"}],  {color: "white", intensity: 2}, "white");  var m = dojo x.gfx3d.matrix;  // 建立空间 var l = view.createCube({bottom: {x: 0, y: 0, z: 0}, top: {x: 100, y: 100, z: 100}}) 		 .setFill({type: "plastic", finish: "dull", color: "lime"});  // 绘制立方体 view.createCylinder({})   // 绘制圆柱体    .setTransform([m.translate(200, 100,200), m.rotateZg(60), m.rotateXg(-60)]) 	 .setStroke("black") 	 .setFill({type: "plastic", finish: "glossy", color: "red"});  var camera = [m.cameraRotateXg(20), m.cameraRotateYg(20),  m.cameraTranslate(-200, -200, 0)]; // 设置摄像机方位 view.applyCameraTransform(camera);  view.render();  };  dojo.addOnLoad(makeObjects);

运行,结果如下图所示。

图 13. Gfx-3D 简单绘图示例

图 13. Gfx-3D 简单绘图示例

其他 DojoX Widget

DojoX 的 widget 包中还提供了更多的小部件,非常的方便易用,本文的最后再来两个餐后甜点,拾色器和鱼眼。拾色器是我们经常会用到的小部件,用 DojoX 生成拾色器非常简单,仅需要 清单 20这一小段代码即可。

清单 20. 拾色器
 

除了这段 javascript 代码,为了能正确的显示拾色器的样式,我们还需要导入它的 css 文件:dojox/widget/ColorPicker/ColorPicker.css。代码中,属性 animatePoint 来确定指针是否有滑动动画,默认为 true;属性 showHsv 表示是否显示 HSV 颜色模式数值;属性 showRgb 表示是否显示 RGB 颜色模式的数值;webSafe 表示是否显示 Web 安全色。清单 20显示效果如下:

图 14 .DojoX 拾色器

图 14 .DojoX 拾色器

鱼眼的实现也很简单,我们需要制作一组图标,命名为 fe1.gif、fe2.gif、fe3.gif 一直到 fe7.gif。我们将它们和页面放在同一文件夹下。然后在网页中书写如 清单 21所示代码。

清单 21. 鱼眼
 

运行,鼠标移上去来看看效果。

图 15.DojoX 鱼眼

图 15 DojoX 鱼眼

结束语

JavaScript 并不是万能的,同样,使用 JavaScript 开发的 Dojo 也不是万能的,但是为了满足众多开发者的需要,DojoX 提供了非常丰富的选择,并且提供了对 Flash、SilverLight、Google Gear 等组件的支持,使得 Dojo 爱好者们可以开发出更好更强大的 Web 应用。随着 DojoX 项目的不断完善和成熟,Dojo 将给开发者们带来更多的惊喜。

 

 var layout = [ 		 {field: 'pro_no', name: 'Product Number' }, 		 {field: 'pro', name: 'Product' }, 		 {field: 'min_amo unt', name: 'Minimum Amount' }, 		 {field: 'max_amount', name: 'Maximum Amount' }, 		 {field: 'avg_amount', name: 'Average Amount' }  ];

 var sampleData = {  identifier: 'pro_no',  label: 'pro_no',  items: [  {pro_no:'2100', pro:'A Series', min_amount:346, max_amount:931, avg_amount:647},  {pro_no:'2200', pro:'B Series', min_amount:301, max_amount:894, avg_amount:608},  {pro_no:'2300', pro:'C Series', min_amount:456, max_amount:791, avg_amount:532},  {pro_no:'2400', pro:'D Series', min_amount:859, max_amount:2433, avg_amount:1840},  {pro_no:'2500', pro:'E Series', min_amount:459, max_amount:1433, avg_amount:1040}  ]  };  var jsonStore = new dojo.data.ItemFileReadStore({ data: sampleData });

 

     first Grid              
First Grid

 
Product Number Product Minimum Amount Maximum Amount Average Amount

 dojo.addOnLoad(function(){  // 指定页面加载完毕后执行 var grid = new dojox.grid.DataGrid({ 	 query: { pro_no: '*' }, 	 id: 'grid2', 	 store: jsonStore, 	 structure: [ 		 {field: 'pro_no', name: 'Product Number' }, 		 {field: 'pro', name: 'Product' }, 		 {field: 'min_amount', name: 'Minimum Amount' }, 		 {field: 'max_amount', name: 'Maximum Amount' }, 		 {field: 'avg_amount', name: 'Average Amount' }  ],rowsPerPage: 20  	 }, 'gridNode');  // 设置 grid 显示在 id 为 gr idNode 的节点下 grid.startup();  // 启动 grid  });

 function formatAmount(value){ 	 return '$ ' + value;  }  function getRange(rowIndex, item){ 	 if(!item){return '--';} 	 var grid = dijit.byId('grid'); 	 var max = grid.store.getValue(item, "max_amount"); 	 var min = grid.store.getValue(item, "min_amount"); 	 return max - min;  }  var subrow1 = [  {field: 'pro_no', name: 'Product Number', rowSpan: 2 },  {field: 'pro', name: 'Product', rowSpan: 2 },  {field: 'min_amount', name: 'Min. Amount',formatter: formatAmount,width: '80px' },  {field: 'avg_amount', name: 'Average Amount',formatter: formatAmount, rowSpan: 2 },  {fiel d: 'range', name: 'Range',get:getRange, rowSpan: 2 }  ];  var subrow2 = [ 	 {field: 'max_amount', name: 'Max. Amount',formatter: formatAmount},  ];  var layout = [subrow1,subrow2];

 var structure = [[ 	 {field: 'type', name: 'Type', rowSpan: 2}, 	 {field: 'pro', name: 'Product', rowSpan: 2}, 	 {field: 'Q20071', name: 'Q1',formatter: formatAmount }, 	 {field: 'Q20072', name: 'Q2',formatter: formatAmount }, 	 {field: 'Q20073', name: 'Q3',formatter: formatAmount }, 	 {field: 'Q20074', name: 'Q4',formatter: formatAmount }   ],[ 	 {field: 'Y2007', name: 'Year 2007',formatter: formatAmount, colSpan: 4 }  ]];

 

     dojo.require("dojo.data.ItemFileWriteStore");  dojo.require("dojox.grid.DataGrid");  // 下面两个包用来创建右键弹出菜单 dojo.require("dijit.Menu");  dojo.require("dojox.widget.PlaceholderMenuItem");  // 使用 dataGrid.txt 中的数据作为填充 DataGrid 的数据 var jsonStore = new dojo.data.ItemFileWriteStore({ url:'dataGrid.txt'});  var layout = [  {feld: 'emp_no', name: 'Employee Number'},  {field: 'name', name: 'Name', editable: true },  // 该列可编辑 {field: 'gender', name: 'Gender', editable:true,  type:dojox.grid.cells.Select, options:['F','M'] }, // 编辑该列时使用下拉菜单 {field: 'dept_no', name: 'Deptment Number', editable:true,  type:dojox.grid.cells.Select, options:['730','731','732','733','734','735']},  {field: 'bonus', name: 'Bonus', editable: true }  ];  dojo.addOnLoad(function(){  var grid = new dojox.grid.DataGrid({  query: { emp_no: '*' },  // 查询字符串 id: 'grid2',            //DataGrid 的 id  autoWidth:true,        // 自动调整宽度 store: jsonStore,       // 使用 jsonStore 对象 structure: layout,       // 使用 layout 对象定义的结构 rowsPerPage: 20,       // 每页读取 20 条记录,保证 Web 浏览器的性能 headerMenu: gridMenu  // 指定头菜单为 gridMenu 			 }, 'gridNode'); 			 grid.startup(); //grid 生效			 }); 			 

   
Data Grid

 { 	 identifier: 'emp_no', 	 label: 'emp_no', 	 items: [      {emp_no:'2100', name:'Matt', gender:'M', dept_no:730, bonus:647}, 	 {emp_no:'2200', name:'Lisa', gender:'F', dept_no:731, bonus:608}, 	 {emp_no:'2300', name:'Mick', gender:'M', dept_no:732, bonus:532}, 	 {emp_no:'2400', name:'John', gender:'M', dept_no:733, bonus:1840}, 	 {emp_no:'2500', name:'Jan', gender:'M', dept_no:734, bonus:1040}, 	 {emp_no:'2101', name:'Jeff', gender:'M', dept_no:730, bonus:647}, 	 {emp_no:'2202', name:'Frank', gender:'M', dept_no:731, bonus:608}, 	 {emp_no:'2303', name:'Fred', gender:'M', dept_no:732, bonus:532}  ]}

  …… 

 chart = new dojox.charting.Chart2D("chart2");  chart.setTheme(dojox.charting.themes.PlotKit.orange);  chart.addAxis("x", {origin:"max"});  chart.addAxis("y", {vertical: true, leftBottom: true, min: 5000, max: 8000,  majorTickStep: 500, minorTickStep: 100});  chart.addPlot("plot1", {type: "Areas", hAxis:"x", vAxis:"y"});  chart.addPlot("plot2", {type: "Grid", hAxis:"x", vAxis:"y"});  data1 = [{x:10,y:7200}, {x:20,y:6800}, {x:30,y:7000}, {x:40,y:6600}, {x:50,y:7000},  {x:60,y:6800}, {x:70,y:7200}, {x:80,y:6600}, {x:90,y:6800}, {x:100,y:7000}];  data2 = [{x:10,y:6800}, {x:20,y:5800}, {x:30,y:6400}, {x:40,y:5600}, {x:50,y:6000},  {x:60,y:6200}, {x:70,y:6600}, {x:80,y:7200}, {x:90,y:6300}, {x:100,y:6000}];  data3 = [{x:10,y:6000}, {x:20,y:6300}, {x:30,y:6800}, {x:40,y:6200}, {x:50,y:6200},  {x:60,y:6600 }, {x:70,y:6300}, {x:80,y:6200}, {x:90,y:6000}, {x:100,y:5900}];  chart.addSeries("series B", data2, {plot: "plot1"});  chart.addSeries("series C", data3, {plot: "plot1"});  chart.addSeries("series A", data1, {plot: "plot1"});  chart.render();

 dojo.require("dojox.charting.Chart2D");  dojo.require("dojox.charting.themes.PlotKit.blue");  dojo.addOnLoad(function() {    var period = 2 * Math.PI;    var tick = Math.PI / 180.0;    var step = 5*Math.PI / 180.0;    var chart = new dojox.charting.Chart2D('chart_area');    chart.setTheme(dojox.charting.themes.PlotKit.blue);    chart.addAxis("x", {min: 0, max: period, majorT ickStep: tick*30,                    minorTickStep: tick*10, minorLabels: false, font: '40px bold'});    chart.addAxis("y", {vertical: true, min: -1.01, max: 1, majorTickStep: 0.5,                    minorTickStep: 0.1, minorLabels: false, font: '40px bold'});    chart.addPlot("default", {type: 'Lines'});    chart.addPlot("grid", {type: "Grid", vMinorLines: true});    var series = {'sin' : [], 'cos' : []};    for(var i = 0; i < period; i+=step) {       series.sin.push({'x' : i, 'y' : Math.sin(i)});       series.cos.push({'x' : i, 'y' : Math.cos(i)});    }  chart.addSeries('sin', series.sin);  chart.addSeries('cos', series.cos);  chart.render();  });

 dojo.require("dojox.charting.Chart3D");  dojo.require("dojox.charting.plot3d.Bars");  dojo.require("dojox.charting.plot3d.Cylinders");  makeObjects = function(){  var m = dojox.gfx3d.matrix;  var chart = new dojox.charting.Chart3D("test",  {lights:   [{direction: {x: 5, y: 5, z: -5}, color: "white"}], 	 ambient:  {color:"white", intensity: 2}, 	 specular: "white"},  [m.cameraRotateXg(10), m.cameraRotateYg(-10), m.scale(0.8),  m.cameraTranslate(-50, -50, 0)]  );  var plot1 = new dojox.charting.plot3d.Bars(500, 500, {gap: 10, material: "yellow"});  plot1.setData([2,1,2,1,1,1,2,3,5]);  chart.addPlot(plot1);  var plot2 = new dojox.charting.plot3d.Bars(500, 500, {gap: 10, material: "red"});  plot2.setData([1,2,3,2,1,2,3,4,5]);  chart.addPlot(plot2);  var plot3 = new dojox.charting.plot3d.Cylinders (500, 500, {gap: 10, material: "#66F"});  plot3.setData([2,3,4,3,2,3,4,5,5]);  chart.addPlot(plot3);  var plot4 = new dojox.charting.plot3d.Cylinders (500, 500 , {gap: 10, material: "#E6F"});  plot4.setData([3,4,5,4,3,4,5,5,5]);  chart.addPlot(plot4);  chart.generate().render();  };  dojo.addOnLoad(makeObjects);

 dojo.require("dojox.gfx");  surface = dojox.gfx.createSurface(dojo.byId("gfx_holder"), 700, 700);  surface.createRect({x: 260, y: 260, width: 50, height: 50}).setFill("#AAF");  surface.createLine({x1: 100, y1: 400, x2: 400, y2: 350}) 	 .setStroke({color:"#9F3",width:5});  surface.createCircle({cx: 200, cy: 200, r: 50}) 	 .setFill("#FEF").setStroke({color: "#F9A", width: 3});  var path="M153 334 " + 		"C153 334 151 334 151 334 C151 339 153 344 156 344 " + 		"C164 344 171 339 171 334 C171 322 164 314 156 314 " + 		"C142 314 131 322 131 334 C131 350 142 364 156 364 " + 		"C175 364 191 350 191 334 C191 311 175 294 156 294 " + 		"C131 294 111 311 111 334 C111 361 131 384 156 384 " + 		"C186 384 211 361 211 334 C211 300 186 274 156 274" surface.createPath(path).setFill("rgb(FF,FF,FF)").setStroke({color:"red",width:3});

 dojo.require("dojox.gfx3d");  makeObjects = function(){  var surface = dojox.gfx.createSurface("test", 500, 500);  var view = surface.createViewport();  // 建立视图 view.setLights([{direction: {x: 0, y: 0, z: -10}, color: "white"}, 			 {direction: {x: 10, y: 0 , z: -10}, color: "#444"}],  {color: "white", intensity: 2}, "white");  var m = dojox.gfx3d.matrix;  // 建立空间 var l = view.createCube({bottom: {x: 0, y: 0, z: 0}, top: {x: 100, y: 100, z: 100}}) 		 .setFill({type: "plastic", finish: "dull", color: "lime"});  // 绘制立方体 view.createCylinder({})   // 绘制圆柱体    .setTransform([m.translate(200, 100,200), m.rotateZg(60), m.rotateXg(-60)]) 	 .setStroke("black") 	 .setFill({type: "plastic", finish: "glossy", color: "red"});  var camera = [m.cameraRotateXg(20), m.cameraRotateYg(20),  m.cameraTranslate(-200, -200, 0)]; // 设置摄像机方位 view.applyCameraTransform(camera);  view.render();  };  dojo.addOnLoad(makeObjects);

 

 

参考资料

学习

  • http://dojotoolkit.org,dojo 官方站点,关于 dojo 最权威的站点。
  • http://dojocampus.org, Dojo 在线课程和教程。
  • 学习 本系列其他部分的内容,了解更多 Dojo 的实用技术。
  • http://www.openajax.org/index.php, 了解更多 Ajax 技术。
  • http://www.ibm.com/developerworks/cn/ajax/, Ajax 资源中心:developerWorks 上所有有关 Ajax 的问题都可以在这里找到解答。
  • “基于 Dojo 的本地化开发”(developerWorks,2008 年 1 月):本文介绍了基于 Dojo 的本地化的实现,通过实例讲解了如何利用 Dojo 提供的本地化支持模块来实现软件的本地化。
  • “提高基于 Dojo 的 Web 2.0 应用程序的性能”(developerWorks,2008 年 2 月):本文通过演示一些实用的技巧来提高 Dojo 的性能,帮助开发人员找出 Web 2.0 应用程序的性能瓶颈。
  • “使用 Dojo 开发支持 Accessibility 的 Web 应用”(developerWorks,2008 年 5 月):帮助开发人员了解 Accessibility 的基本内容,掌握 Dojo 开发可访问性 Web 应用的基本技能。
  • “使用 Dojo 国际化 Web 应用程序”(developerWorks,2008 年 8 月):通过本文获得有关如何使用 Dojo 这个重要特性的简短的指导。
  • wikipedia上关于 XMLHttpRequest 对象的详细介绍。
  • JSON 的官方网站,在这里可以找到最实用的关于 JSON 的第一手资料。
  • Wikipedia 上关于 REST 架构风格的介绍。
  • developerWorks 技术活动和 网络广播:随时关注 developerWorks 技术活动和网络广播。
  • developerWorks Web development 专区:通过专门关于 Web 技术的文章和教程,扩展您在网站开发方面的技能。

获得产品和技术

  • 下载最新版 Dojo 工具包。

讨论

  • 访问 Dojo 发起人 Alex Russell 的博客:有很多有深度的文章。

参考资料

学习

  • http://dojotoolkit.org,dojo 官方站点,关于 dojo 最权威的站点。
  • http://dojocampus.org, Dojo 在线课程和教程。
  • 学习 本系列其他部分的内容,了解更多 Dojo 的实用技术。
  • http://www.openajax.org/index.php, 了解更多 Ajax 技术。
  • http://www.ibm.com/developerworks/cn/ajax/, Ajax 资源中心:developerWorks 上所有有关 Ajax 的问题都可以在这里找到解答。
  • “基于 Dojo 的本地化开发”(developerWorks,2008 年 1 月):本文介绍了基于 Dojo 的本地化的实现,通过实例讲解了如何利用 Dojo 提供的本地化支持模块来实现软件的本地化。
  • “提高基于 Dojo 的 Web 2.0 应用程序的性能”(developerWorks,2008 年 2 月):本文通过演示一些实用的技巧来提高 Dojo 的性能,帮助开发人员找出 Web 2.0 应用程序的性能瓶颈。
  • “使用 Dojo 开发支持 Accessibility 的 Web 应用”(developerWorks,2008 年 5 月):帮助开发人员了解 Accessibility 的基本内容,掌握 Dojo 开发可访问性 Web 应用的基本技能。
  • “使用 Dojo 国际化 Web 应用程序”(developerWorks,2008 年 8 月):通过本文获得有关如何使用 Dojo 这个重要特性的简短的指导。
  • wikipedia上关于 XMLHttpRequest 对象的详细介绍。
  • JSON 的官方网站,在这里可以找到最实用的关于 JSON 的第一手资料。
  • Wikipedia 上关于 REST 架构风格的介绍。
  • developerWorks 技术活动和 网络广播:随时关注 developerWorks 技术活动和网络广播。
  • developerWorks Web development 专区:通过专门关于 Web 技术的文章和教程,扩展您在网站开发方面的技能。

获得产品和技术

  • 下载最新版 Dojo 工具包。

讨论

  • 访问 Dojo 发起人 Alex Russell 的博客:有很多有深度的文章。

Leave a Comment

Your email address will not be published.