Introduction

Using ZK Charts allows you to create charts based on your own data in a much efficient way than before. In this blog, we will show you how you can paint the time plot chart using ZK Charts instead of the SIMILE Timeplot Component.

Installation

ZK Charts version: 1.2.0+
If you are not familiar with ZK Charts component, please take a look at Getting Started with ZK Charts

Demo

Data Preparation

In this demo, we will use the same data as the example of SIMILE timeplot, which contains New Legal Permanent Residents in the U.S. (per year) vs. U.S. History. We declare the data into two two-dimension arrays for data(Residents) and events(History) in a TimeplotData class as the following:

public class TimeplotData {
	private static final Object[][] events = {
		{getDate(1849, 1, 1), "California Gold Rush"},
		// omitted
		{getDate(2001, 9, 11), "Attack at the World Trade Center"}
	};
	private static final Double[][] data = {
		{getDate(1820, 1, 1), 8385d},
		// omitted
		{getDate(2006, 1, 1), 1266264d}};

	static Double[][] getData() {
		return data;
	}
	static Object[][] getEvents() {
		return events;
	}

	static Double getDate(int year, int month, int date) {
		Calendar cal = Calendar.getInstance();
		cal.setTimeZone(TimeZone.getTimeZone("UTC"));
		cal.set(year, month, date);
		return (double) cal.getTimeInMillis();
	}
}

Declare ZK Composer

Declaring this TimeplotComposer class normally as you would using any other ZK components, we then put the styling code of the chart into the doAfterCompose() method and initiate the chart into the doZoomOut() method as follows:

public void doAfterCompose(Window comp) throws Exception {
		super.doAfterCompose(comp);

		// set the xAxis type to support datetime format
		XAxis xAxis = chart.getXAxis();
		xAxis.setType("datetime");

		// styling the chart layout
		YAxis yAxis = chart.getYAxis();
		yAxis.setTitle("Value");
		yAxis.setMin(0);
		yAxis.setGridLineWidth(0);
		yAxis.setLineWidth(1);

		// specify the simple tooltip for the point format
		chart.getTooltip().setPointFormat("{point.x:%e. %b}: {point.y}");
		
		// disable the legend in this chart
		chart.getLegend().setEnabled(false);
		
		// paint the time plot chart by using
		// the same zoom out API (the default zoom value is 1)
		doZoomOut();
}

Register the two events – onSelection for ZK Charts and onClick for ZK Button, the onSelection event in this demo demonstrates the zooming functionality of ZK Charts, and the other is to reset the zooming to scale.

For example,

	@Listen("onSelection = #chart")
	public void doSelection(ChartsSelectionEvent event) {
		// doing the zooming in function
		double min = event.getXAxisMin().longValue();
		double max = event.getXAxisMax().longValue();
		updateSelection(min, max);
		
		// enable the zooming out button
		btn.setVisible(true);
	}

	@Listen("onClick = #btn")
	public void doZoomOut() {
		Double[][] data = TimeplotData.getData();
		updateSelection(data[0][0], data[data.length-1][0]);
		btn.setVisible(false);
	}

And then we paint the data on the timeplot chart within updateSelection() method, which depends on the selection range, if any.

	private void updateSelection(double min, double max) {
		// reset
		XAxis xAxis = chart.getXAxis();

		if (xAxis.getPlotBands() != null) {
			for (PlotBand pb : new ArrayList<PlotBand>
					(xAxis.getPlotBands())) {
				xAxis.removePlotBand(pb);
			}
		}
		if (xAxis.getPlotLines() != null) {
			for (PlotLine pl : new ArrayList<PlotLine>
					(xAxis.getPlotLines())) {
				xAxis.removePlotLine(pl);
			}
		}

		Series series1 = chart.getSeries();
		
		// styling the color of the point
		AreaPlotOptions area = chart.getPlotOptions().getArea();
		area.setLineColor("rgba(0,139,182,1)");
		Marker marker = chart.getPlotOptions().getArea().getMarker();
		marker.setRadius(2);
		
		// styling the color of the series	
		LinearGradient seriesColor = new LinearGradient(1, 0, 1, 1);
		seriesColor.addStop(0, "rgba(0,139,182,1)");
		seriesColor.addStop(1, "rgba(255,255,255,0.5)");
		series1.setColor(seriesColor);
		
		// styling the color of the plotband	
		LinearGradient plotbandColor = new LinearGradient(1, 1, 1, 0);
		plotbandColor.addStop(0, "#008bb6");
		plotbandColor.addStop(1, "#ffffff");
		
		series1.setType("area");
		List<Point> data = series1.getData();
		if (data != null)
			data.clear();
		
		// fill in the data of New Legal Permanent Residents in the U.S
		for (Double[] val : TimeplotData.getData()) {
			if (min < val[0] && max > val[0]) {
				Point point = new Point(val[0], val[1]);
				point.setColor("blank");
				series1.addPoint(point);
			}
		}
		
		// fill in the data of the U.S. History
		for (Object[] val : TimeplotData.getEvents()) {
			if (val.length == 2) {
				
				// without the end date, we use PlotLine to display
				if (min < (Double) val[0] && max > (Double) val[0]) {
					PlotLine line = new PlotLine();
					final String title = (String) val[1];
					line.setValue((Number) val[0]);
					line.setWidth(3);
					line.setColor("rgba(0,139,182,0.5)");
					line.addEventListener("onMouseOver",
						new EventListener<MouseEvent>() {
							public void onEvent(MouseEvent event)
								throws Exception {
							Clients.showNotification(title, "info",
								event.getTarget(),
								event.getPageX() == 0 ? 
									event.getX() : event.getPageX(),
								event.getPageY() == 0 ?
									event.getY() : event.getPageY()
								, 1500, false);
							}
						});
					xAxis.addPlotLine(line);
				}
			} else {
				double v0 = (Double) val[0];
				double v1 = (Double) val[1];
				if (v0 < min && v1 < max)
					v0 = min;
				if (v0 > min && v1 > max)
					v1 = max;
				if (v0 < min && v1 > max) {
					v0 = min;
					v1 = max;
				}

				// with the end date, we use PlotBand to display
				if (min <= v1 && max >= v1) {
					final PlotBand band = new PlotBand();
					band.setFrom((Number) val[0]);
					band.setTo((Number) val[1]);
					band.setColor(plotbandColor);
					final String title = (String) val[2];
					band.addEventListener("onMouseOver",
						new EventListener<MouseEvent>() {
							public void onEvent(MouseEvent event)
								throws Exception {
							Clients.showNotification(title, "info",
								event.getTarget(),
								event.getPageX() == 0 ?
									event.getX() : event.getPageX(),
								event.getPageY() == 0 ?
									event.getY() : event.getPageY(),
									1500, false);
							}
						});
					xAxis.addPlotBand(band);
				}
			}
		}
	}

As you can see from the above, we used PlotBand (a rectangular area in the graph) and PlotLine to represent the events (U.S. History) on the chart.

Declare the Chart in a ZUL file

<?script src="/js/notification.js"?>
<zk>
	<window apply="org.zkoss.blog.timeplot.TimeplotComposer">
	    <charts id="chart" zoomType="x"
		 enableZoomSelection="false" title="ZK Timeplot"/>
	    <button id="btn" visible="false" label="Reset Zoom"/> 
	</window>
</zk>

We provide a notification.js to overwrite the default ZK notification tooltip behavior in order to center the tooltip when mouse hovering the event bar (timeline). We also provide a button the in the chart to reset the zooming.

Download
All example code can be found in the github project

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.

Leave a Reply