用 Java绘图一直都吸引着开发人员的注意传统上Java 开发人员使用 javaawtGraphics 或 Java D API 进行绘图一些开发人员甚至使用现成的开源工具箱(如 JSci)来绘图但很多时候您的选择被限定在了 AWT 或 Swing 上为了最大限度地减少对第三方工具箱的依赖或者为了简化绘图基础可以考虑使用 DrawD并编写自己的代码来制图或绘图
DrawD 简介
DrawD 是一个驻留在 SWT Composite 之上的轻量级窗口小部件系统一个 DrawD 实例 由一个 SWT Composite一个轻量级系统及其内容的图形组成图形 是 DrawD 的构建块关于 DrawD API 的所有细节可以从 DrawD Developers Guide 的 Eclipse 帮助文件中找到因为本文不打算成为一篇讲述 DrawD 的教程所以为了简便起见只要您了解 DrawD API 可以帮助您在 SWT Canvas 上进行绘图就足够了您可以直接使用一些标准的图形比如 EllipsePolylineRectangleFigure 和 Triangle或者您可以扩展它们来创建自己的图形此外一些容器图形如 Panel可以充当所有子图形的总容器
DrawD 有两个重要的包orgeclipsedrawdgeometry 和 orgeclipsedrawdgraph本文中使用了这两个包orgeclipsedrawdgeometry 包有一些有用的类比如 RectanglePoint 和 PointList这些类都是自我解释的另一个包 orgeclipsedrawdgraph 开发人员使用的可能不是太多这个包提供了一些重要的类比如 DirectedGraphNodeEdgeNodeList 和 EdgeList这些类有助于创建图表
在本文中我将解释如何使用 DrawD 编写代码帮助您以图形的方式形象化您的数据我将从一项技术的描述开始该技术将位于某一范围内的数据值(比如从 到 )按比例缩放成另一范围内的等效数据值(例如从 到 )然后我将举例说明如何绘制出任意个级数的 XY 坐标图每个级数都包含一组数据元素在学习了本文中的概念之后就可以很容易地绘制其他类型的图表比如饼图和条形图
具体的绘图过程
步骤 您想绘制什么样的图形?
显然您想以图形方式描绘来自数据源的数据所以您需要那些您想以图形形式形象化的数据为了简便起见我使用了一个名为 dataGenerator 的简单函数生成的数据而不是从 XML 文件或其他一些数据源读取数据该函数使用了一个 for(;;) 循环并以数组列表的形式返回生成的值
清单 生成一些数据
private ArrayList dataGenerator() {
double series[] = new double[];
for(int i=; iseries1[i] = (i*10) + 10; // a linearseries containing 10,20,30,40,50
double series2[] = new double[9];
series2[0] = 20; series2[1] = 150; series2[2] = 5;
series2[3] = 90; series2[4] = 35;series2[5] = 20;
series2[6] = 150; series2[7] = 5; series2[8] = 45;
double series3[] = new double[7];
for(int i=0; iseries3[i] = (i*20) + 15;seriesData.add(series1);
seriesData.add(series2);
seriesData.add(series3);
return seriesData;
}
步骤 2:缩放技术 —— 从给定的数据生成 X 坐标和 Y 坐标
一些新的术语
FigureCanvas
Draw2D 中的 FigureCanvas 是 SWT Canvas 的一个扩展。tw.WInGwiT.COMFigureCanvas 可以包含 Draw2D 图形。
Panel
Panel 是 Draw2D 中的一个通用容器图形,它可以包含子图形。您可以向一个 Panel 图形中添加许多图形,然后将这个 Panel 图形提供给 FigureCanvas。
DirectedGraph
DirectedGraph 是一个 2-D 图形,拥有有限数量的 Node,每个 Node 都位于一些 Point 中,相邻的 Node 是通过 Edges 彼此连接在一起的。
当您想绘制一架 2-D 飞机上的点时,必须找出每个点的 X 坐标和 Y 坐标。绘图的奇妙之处在于能够将某一个给定数据值从一个范围按比例缩放到另一个范围中,也就是说,如果给定一组值,如 {10,20,30},那么您应该能够确定 2-D 飞机上具体哪些点(X 坐标和 Y 坐标)表示的是 10、20 和 30 这些数据值。
绘制总是在按照某一个限定缩放比例进行的。换句话说,在同一限定区域内,可以绘制任意数量的点。因为该区域是固定的,所以您总是可以找到 X 坐标轴的跨度(长度)和 Y 坐标轴的跨度(高度)。X 坐标轴和 Y 坐标轴的跨度只是等式的一部分。另一部分是找出数据值的范围,并根据每个数据值在新范围内的等效值来计算这些值的坐标。
计算 X 坐标和 Y 坐标
X 坐标:X 坐标是某一个点距离原点的水平距离。计算元素的数量,然后将 X 坐标轴的跨度分成 n 个区段,其中,n 是给定集合中的元素的数量,通过这种方式,可以计算某一集合中的所有点的横向坐标。用这种分割方法可以获得每个区段的长度。集合中的第一个点位于等于区段长度的第一段距离内。后续的每个点则位于区段长度加上原点到前一个点的距离的那一段距离内。
例如,给出一个集合 {10,20,30,40},您立刻就可以知道要绘制 4 个点,因为集合中包含 4 个元素。所以,应该将 X 坐标轴的跨度分成 4 个相等的区段,每个区段的长度 = 跨度/4。因此,如果 X 坐标轴的跨度是 800,那么区段的长度将是 800/4,即 200。第一个元素(10)的 X 坐标将是 200,第二个元素(20)的 X 坐标将是 400,依此类推。
清单 2. 计算 X 坐标
private int[] getXCoordinates(ArrayList seriesData){
int xSpan = (int)GraFixConstants.xSpan;
int longestSeries = Utilities.getLongestSeries(seriesData);
int numSegments =
((double[])seriesData.get(longestSeries)).length;
int sectionWidth =
(int)xSpan / numSegments; //want to divide span of xAxis
int xPositions[] =
new int[numSegments]; // will contain X-coordinate of all dots.
for(int i=0; ixPositions[i]=(i+1)*sectionWidth;//dots spaced at distance of sectionWidth
}
return xPositions;
}
Y 坐标:Y 坐标是某一个点距离原点的纵向距离。计算 Y 坐标要将某一个值按比例从一个范围缩放到另一个范围。例如,给出相同的集合 {10,20,30,40},您可以看出,数据的范围是 0 到 40,新的范围就是 Y 坐标轴的跨度(高度)。假设 Y 坐标轴的高度为 400,那么第一个元素(10)的高度将是100,第二个元素的高度将是 200,依此类推。
通过以下例子,您可以更好地理解如何按比例将一个值从一个范围缩放到另一个范围:假定一个范围的跨度是从 0 到 2048,而您打算将该范围内的任意值(比如说 1024)缩放到另一个从 0 到 100 的范围内,那么您立刻就可以知道,等刻度值是 50。该缩放所遵循的三值线算法是:
line 1---> 2048 / 1024 equals 2.
line 2---> 100 - 0 equals 100.
line 3---> / equals which is the desired scaled value
步骤 您想在哪儿进行绘图?
您还需要进行绘图的地方可以通过扩展 Eclipse ViewPart 和使用 SWT Composite 来创建您自己的视图此外也可以使用从 main() 函数中调用的 SWT shell
在扩展 Eclipse ViewPart 时至少必须实现两个函数createPartControl(Composite parent) 和 setFocus()函数 createPartControl(Composite parent) 是在屏幕上绘制视图时自动调用的您的兴趣只在所接收的 SWT Composite 上因此将它传递给某个类然后通过对这个类进行编码来绘制图形
清单 使用 Eclipse ViewPart 绘图
public class MainGraFixView extends ViewPart{
public void createPartControl(Composite parent) {
//create or get data in an arraylist
ArrayList seriesData = dataGenerator();
//instantiate a plotter and provide data to it
DirectedGraphXYPlotter dgXYGraph = new DirectedGraphXYPlotter(parent);
dgXYGraphsetData(seriesData);
dgXYGraphplot(); //ask it to plot
}
public void setFocus() {
}
}
步骤 您需要绘制哪种图形?
一旦拥有了数据以及想用来绘制图形的区域就必须确定您需要哪种类型的可视化在本文中我演示了如何编写代码来创建 XY 坐标图和线形图一旦知道了绘制 XY 坐标图的技术就应该能够绘制出其他图形比如条形图和饼图要想更多地了解 XY 坐标图请参阅我为本文编写的 DirectedGraphXYPlotter 类(参见所附源代码中的 \src\GraFix\Plotters\DirectedGraphXYPlotterjava)
步骤 创建自己的 XY 坐标图
XY 坐标图应该能够绘制出 D 飞机上的任意数量的级数线每个级数线都应该以图形形式显示出引用 X 和 Y 引用线的那些级数中的每个点的位置每个点都应该通过一条线连接到级数中的下一个点上通过使用表示一个点和一条线的 DrawD 图形您应该能够创建这样一个坐标图例如为了表示一个点我通过扩展 Ellipse 图形创建了一个 Dot 图形并使用 PolylineConnection 图形来表示连接线
Direc