Drawing with Java has always attracted the attention of developers. Traditionally, Java developers use Java. AWT. graphics or Java 2D APIs for plotting. Some developers even use ready-made open-source toolboxes (such as JSCI) for plotting. However, in many cases, your choice is limited to AWT or swing. To minimize dependencies on third-party toolboxes, or to simplify the drawing basics, consider using draw2d and writing your own code for plotting or plotting.
Introduction to draw2d
Draw2d is a lightweight Window widget system residing on SWT composite. A draw2dInstanceConsists of a SWT composite, a lightweight system, and a graph of its content.GraphicsIs the building block of draw2d. For details about the draw2d API, refer to the eclipse help file of the draw2d developer's guide. Because this article is not intended to be a draw2d tutorial, it is sufficient to understand the draw2d API to help you draw on the SWT canvas for simplicity. You can directly use standard images, such as ellipse, polyline, rectanglefigure, and triangle, or expand them to create your own images. In addition, some container graphics, such as panel, can act as the total container of all sub-graphics.
Draw2d has two important packages: org. Eclipse. draw2d. Geometry and org. Eclipse. draw2d. graph. These two packages are used in this article. The Org. Eclipse. draw2d. geometry package has some useful classes, such as rectangle, point, and pointlist, which are self-explanatory. Another package, org. Eclipse. draw2d. graph, may not be used too much. This package provides important classes, such as directedgraph, node, edge, nodelist, and edgelist, which help you create charts.
In this article, I will explain how to use draw2d to write code and help you visualize your data graphically. I will start with a description of a technology that will be in a certain range of data values (for example, from 0 to 2048) scales proportionally to the equivalent data value in another range (for example, from 0 to 100 ). Then I will illustrate how to plot the X-Y Coordinate Map for any level, each level contains a set of data elements. After learning the concepts in this article, you can easily draw other types of charts, such as pie charts and bar charts.
Specific Drawing Process
Step 1: What kind of image do you want to draw?
Obviously, you want to graphically depict data from the data source. Therefore, you need data that you want to visualize in graphs. For convenience, I used a simple function named datagenerator to generate data instead of reading data from an XML file or some other data sources. This function uses a for (;) loop, and return the generated value in the form of an array list.
Listing 1. generating some data
private ArrayList dataGenerator() { double series1[] = new double[5]; for(int i=0; i<series1.length; i++) series1[i] = (i*10) + 10; // a linear series 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; i<series3.length; i++) series3[i] = (i*20) + 15; seriesData.add(series1); seriesData.add(series2); seriesData.add(series3); return seriesData; } |
Step 2: zoom technology-generate X and Y coordinates from the given data
Some new terms
-
Figurecanvas
-
Figurecanvas in draw2d is an extension of SWT canvas. Figurecanvas can contain draw2d images.
-
Panel
-
Panel is a universal container image in draw2d. It can contain subgraphs. You can add Multiple widgets to a panel image and then provide the Panel image to figurecanvas.
-
Directedgraph
-
Directedgraph is a 2-D graph with a limited number of nodes. Each node is located in some points, and adjacent nodes are connected to each other through edges.
|
To draw a point on a 2-D plane, you must find the X and Y coordinates of each point. The magic of plotting is that a given data value can be scaled proportionally from one range to another, that is, if a group of values such as {10, 20, 30} are given }, then you should be able to determine which points (X and Y coordinates) on the 2-D plane represent the 10, 20, and 30 data values.
Plotting is always performed according to a limited scaling ratio. In other words, you can draw any number of points in the same restricted area. Because the area is fixed, you can always find the span (length) of the X axis and the span (height) of the Y axis ). The spans of the X and Y axes are only part of the equation. The other part is to find out the range of data values, and calculate the coordinates of these values based on the equivalent values of each data value in the new range.
Returns X and Y coordinates.
X coordinate: X coordinate is the horizontal distance between a point and the origin. Calculate the number of elements and divide the span of the X axisNCIDR blocks, where,NIs the number of elements in a given set. In this way, you can calculate the horizontal coordinates of all vertices in a set. You can use this method to obtain the length of each segment. The first vertex in the set is within the first distance equal to the segment length. Each subsequent vertex is located within the distance of the segment length plus the distance from the origin point to the previous vertex.
For example, if a set {10, 20, 30, 40} is provided, you can immediately draw four vertices because the set contains four elements. Therefore, the span of the X axis should be divided into four equal segments, with the length of each segment = SPAN/4. Therefore, if the span of the X axis is 800, the segment length will be 800/4, that is, 200. The X coordinate of the first element (10) will be 200, and the X coordinate of the second element (20) will be 400, and so on.
List 2. Calculate the X coordinate
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; i<numSegments; i++){ xPositions[i]= (i+1)*sectionWidth;//dots spaced at distance of sectionWidth } return xPositions; } |
Y coordinate: Y coordinate is the vertical distance between a point and the origin. To calculate the Y coordinate, scale a value proportionally from one range to another. For example, given the same set {10, 20, 30, 40}, you can see that the data range is 0 to 40, and the new range is the span (height) of the Y axis ). If the height of the Y axis is 400, the height of the first element (10) will be 100, and the height of the second element will be 200, and so on.
In the following example, you can better understand how to scale a value from one range to another proportionally: assume that the span of a range is from 0 to 2048, if you want to scale any value in the range (for example, 1024) to another range from 0 to 100, you can immediately know that the scale value is 50. The three-value line algorithm for scaling is as follows:
line 1---> 2048 / 1024 equals 2. line 2---> 100 - 0 equals 100. line 3---> 100 / 2 equals 50, which is the desired scaled value. |
Step 3: Where do you want to draw?
You also need to plot the location. You can use eclipse viewpart extension and SWT composite to create your own views. You can also use the SWT shell called from the main () function.
When extending eclipse viewpart, at least two functions must be implemented: createpartcontrol (composite parent) and setfocus (). The createpartcontrol (composite parent) function is automatically called when a view is drawn on the screen. Your interest is only on the received SWT composite. Therefore, it is passed to a class and then coded to draw the image.
Listing 3. Use eclipse viewpart for plotting
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); dgXYGraph.setData(seriesData); dgXYGraph.plot(); //ask it to plot } public void setFocus() { } } |
Step 4. Which image do you need to draw?
Once you have data and want to draw a graphic area, you must determine the type of visualization you need. In this article, I demonstrated how to write code to create a X-Y coordinate chart and a line chart. Once you know the techniques for drawing X-Y coordinate charts, you should be able to draw other figures, such as bar charts and pie charts. For more information about the X-Y coordinate chart, see the directedgraphxyplotter class I wrote for this article (see/src/grafix/plotters/directedgraphxyplotter. Java in the attached source code ).
Step 5: Create your own X-Y coordinate chart
The X-Y coordinate chart should be able to draw any number of series lines on the 2-D aircraft. Each series line should display the position of each point in the series that reference the X and Y reference lines in graphics. Each point should be connected to the next point in the series through a line. By using a draw2d image that represents a point and a line, you should be able to create such a coordinate chart. For example, to represent a vertex, I create a dot graph by extending the ellipse graph and use the polylineconnection graph to represent a connection line.
The directedgraphxyplotter class has only two common functions: setdata (arraylist seriesdata) and plot (). The setdata function (arraylist seriesdata) accepts the data you want to visualize in graphical form (see step 1), while the plot () function begins plotting.
Once the plot () function is called, the following steps must be followed:
- Use a SWT composite and place figurecanvas on it. Then, place a general container map similar to panel on the canvas.
- Calculate the number of levels to be drawn, and then fill in the number of nodelists and edgelists required to create directedgraphs.
- Draw X and Y axes on the panel chart. (See xrulerbar. Java and yrulerbar. Java in the/src/grafix/figure directory in the source code .)
- Create a directedgraphs with the same number of levels for plotting.
- Draw points and connection lines on the panel chart, and use the graphic data in directedgraphs created in Step D.
- Finally, you can set the canvas content by providing a panel chart, including all the points and connections you have prepared so far.
In the following code:
Listing 4. Plot () function
1. public void plot(){ 2. //if no place to plot, or no data to plot, return. 3. if(null==_parent || null==_seriesData) 4. return; 5. 6. Composite composite = new Composite(_parent, SWT.BORDER); 7. composite.setLayout(new FillLayout()); 8. FigureCanvas canvas = new FigureCanvas(composite); 9. 10. Panel contents = new Panel();//A Panel is a general purpose container figure 11. contents.setLayoutManager(new XYLayout()); 12. initializeSpan(contents.getClientArea()); 13. 14. populateNodesAndEdges(); 15. 16. drawAxis(contents); 17. for(int i=0; i<_numSeries; i++){ 18. drawDotsAndConnections(contents,getDirectedGraph(i)); // draw points & connecting wires 19. } 20. canvas.setContents(contents); 21. } |
Plot () calls two important internal functions to help draw points in the graph: populatenodesandedges () and drawdotsandconnections (). Let's take a look at directedgraph before you find out what functions these two functions have completed.
What is directedgraph?To use draw2d for plotting, you must first create a drawing and define the points and lines to be drawn. Once this graph is created, you can use it to actually draw on the canvas. You can visualize directedgraph as a 2-D graph with a limited number of nodes. In this graph, each node is located on a certain point, and adjacent nodes are connected through edges.
You can use the following code to understand the key to creating directedgraph. First, create a node list and an edges list. Then, create a new directedgraph and set its members (nodes and edges) through the nodelist and edgelist created just now ). Now, use graphvisitor to access this directedgraph. For simplicity, there are many graphvisitor implementations in the org. Eclipse. draw2d. Internal. Graph package. These graphvisitor have specific algorithms used to access graphics.
Therefore, the sample code for creating directedgraph is similar to the following:
Listing 5. Example directedgraph
//This is a sample, you will need to add actual Node(s) to this NodeList. NodeList nodes = new NodeList(); //create a list of nodes. //This is a sample, you will need to add actual Edge(s) to this EdgeList. EdgeList edges = new EdgeList(); //create a list of edges. DirectedGraph graph = new DirectedGraph(); graph.nodes = nodes; graph.edges = edges; new BreakCycles().visit(graph);//ask BreakCycles to visit the graph. //now our "graph" is ready to be used. |
Now we know that directedgraph contains many nodes, each of which may contain some data, and also stores the X and Y coordinates of the data, as well as a list of edges, each edge knows that there is a node at both ends of it. You can use the following technology to plot the information, which involves two parts:
Part A -- fill node and edge by following these steps:
- Create a nodelist. In this list, each element in the SET has a node. The set {10, 20, 30, 40} requires four nodes.
- Find the X and Y coordinates of each element and store them in node. X and node. y member variables.
- Create an edgelist.N-1 edge, where,NIs the number of elements in the set. For example, the set {10, 20, 30, 40} requires three edges.
- Associate node with the left and right sides of each edge, and set the edge. Start and edge. End member variables accordingly.
Part B-draw a node and edge image by following these steps:
- Draw a dot graph to represent each node.
- Draw a polylineconnection graph to represent each edge.
- Define each polylineconnection graph to fix the left and right sides of the dot graph.
Now, return to the Work of Internal functions:
- Function populatenodesandedges () implements Part A of this technology, while function drawdotsandconnections () implements Part B of this technology.
- The populatenodesandedges () function calculates the number of levels to be drawn. It creates a nodelist and an edgelist for each level.
- Each nodelist contains a list of nodes used for special levels. Each node stores information about where the X and Y coordinates should be drawn. The getxcoordinates () and getycoordinates () functions are used to retrieve the X and Y coordinate values respectively. Using the same algorithm in step 2, these functions can also internally scale data values from one range to another proportionally.
- Each edgelist contains a list of edges used for special levels. Each edge has a node on both the left and right sides.
Listing 6. populatenodesandedges () function
private void populateNodesAndEdges(){ _seriesScaledValues = new ArrayList(getScaledValues(_seriesData)); _nodeLists = new ArrayList(); _edgeLists = new ArrayList(); for(int i=0; i<_numSeries; i++){ _nodeLists.add(new NodeList());// one NodeList per series. _edgeLists.add(new EdgeList());// one EdgeList per series. } //populate all NodeLists with the Nodes. for(int i=0; i<_numSeries; i++){//for each series double data[] = (double[])_seriesData.get(i);//get the series int xCoOrds[] = getXCoordinates(_seriesData); int yCoOrds[] = getYCoordinates(i, data); //each NodeList has as many Nodes as points in a series for(int j=0; j<data.length; j++){ Double doubleValue = new Double(data[j]); Node node = new Node(doubleValue); node.x = xCoOrds[j]; node.y = yCoOrds[j]; ((NodeList)_nodeLists.get(i)).add(node); } } //populate all EdgeLists with the Edges. for(int i=0; i<_numSeries; i++){ NodeList nodes = (NodeList)_nodeLists.get(i); for(int j=0; j<nodes.size()-1; j++){ Node leftNode = nodes.getNode(j); Node rightNode = nodes.getNode(j+1); Edge edge = new Edge(leftNode,rightNode); edge.start = new Point(leftNode.x, leftNode.y); edge.end = new Point(rightNode.x, rightNode.y); ((EdgeList)_edgeLists.get(i)).add(edge); } } int breakpoint = 0; } |
Once the function populatenodesandedges () completes its mission, it creates nodelists and edgelists for all the levels to be drawn, and the other function drawdotsandconnections () begins to draw a dot graph for each node, draw a polylineconnection graph for each edge.
Listing 7. drawdotsandconnections (), drawnode (), and drawedge () Functions
private void drawDotsAndConnections(IFigure contents, DirectedGraph graph){ for (int i = 0; i < graph.nodes.size(); i++) { Node node = graph.nodes.getNode(i); drawNode(contents, node); } for (int i = 0; i < graph.edges.size(); i++) { Edge edge = graph.edges.getEdge(i); drawEdge(contents, edge); } } private void drawNode(IFigure contents, Node node){ Dot dotFigure = new Dot(); node.data = dotFigure; int xPos = node.x; int yPos = node.y; contents.add(dotFigure); contents.setConstraint(dotFigure, new Rectangle(xPos,yPos,-1,-1)); } private void drawEdge(IFigure contents, Edge edge){ PolylineConnection wireFigure = new PolylineConnection(); //edge.source is the Node to the left of this edge EllipseAnchor sourceAnchor = new EllipseAnchor((Dot)edge.source.data); //edge.target is the Node to the right of this edge EllipseAnchor targetAnchor = new EllipseAnchor((Dot)edge.target.data); wireFigure.setSourceAnchor(sourceAnchor); wireFigure.setTargetAnchor(targetAnchor); contents.add(wireFigure); } |
Conclusion
Draw2d is a good tool if you want to graphically depict the data to be presented. You can use draw2d to write your own Java code for drawing graphics, which helps you focus on scaling code and drawing code, and leave other work related to drawing to draw2d and SWT. You can also use the selected draw2d image to control the appearance of your image. Draw2d simplifies the Basic Drawing steps and minimizes your dependency on third-party toolboxes.