Using Timeline Component, Part II
Gu Wei Xing, Software developer in NanTong of JiangSu province, China.
Feb 13, 2007
Applicable to ZK 2.2.0 and later.
- Editor's Note:
- This is the second article regarding how to use the timeline component. Here is the Part I.
- The example code described in this article is developed under Eclipse SDK. For how to setup Eclipse with ZK, please refer to this Small Talk.
Introduction
In this small-talk I will demonstrate how to use advanced feature of Timeline component. You can download the source about this small-talk here.
Since we will call the methods of Timeline and Bandinfo so we should name the id of Timeline component and the two bands, say, "tl", "b1", and "b2", respectively. Now let's add these lines to timeline.zul.
import java.util.*;
import org.zkforge.timeline.decorator.*;
//for add and remove OccurEvent
ArrayList events=new ArrayList();
//for filter and highlight
String filter;
String[] highlight=new String[4];
//for decorator
SpanHighlightDecorator shd=new SpanHighlightDecorator(d1,d2);
Add and Remove OccurEvent
OccurEvent is a java class which contains many properties to show in Timeline. For example, start, end, text, and a read-only id property etc. In Bandinfo class there are addOccurEvent and removeOccurEvent interfaces to add or remove an OccurEvent. Note that the band will not maintain the OccurEvents. It only send all properties of OccurEvent to brower side to show it.
<button label="Add OccurEvent">
<attribute name="onClick">
<![CDATA[
import org.zkforge.timeline.*;
import org.zkforge.timeline.data.*;
import java.util.*;
OccurEvent e=new OccurEvent();
Map params=new HashMap();
params.put("event",e);
Window w=(Window)Executions.createComponents("add-event.zul", null, params);
w.doModal();
if(w.getAttribute("OK")){
events.add(e);
b1.addOccurEvent(e);
b2.addOccurEvent(e);
b1.scrollToCenter(e.getStart());
}
]]>
</attribute>
</button>
<button label="Remove OccurEvent">
<attribute name="onClick">
<![CDATA[
import org.zkforge.timeline.data.*;
Map params=new HashMap();
params.put("events",events);
Window w=(Window)Executions.createComponents("remove-event.zul", null, params);
w.doModal();
int index=w.getAttribute("selected");
if(index!=-1){
OccurEvent e=(OccurEvent)events.get(index);
b1.removeOccurEvent(e);
b2.removeOccurEvent(e);
events.remove(index);
b1.scrollToCenter(e.getStart());
}
]]>
</attribute>
</button>
In add-event.zul we use annotation to bind data.
<window title="new occur event window" width="300px"
xmlns:a="http://www.zkoss.org/2005/zk/annotation" id="eventwin">
<zscript>
<![CDATA[
import org.zkforge.timeline.data.*;
OccurEvent e=arg.get("event");
]]>
</zscript>
<grid>
<columns>
<column label="Type" />
<column label="Context" />
</columns>
<rows>
<row>
<label value="Start Date:" />
<a:bind value="e.start" />
<datebox />
</row>
<row>
<label value="End Date:" />
<a:bind value="e.end" />
<datebox />
</row>
<row>
<label value="Text:" />
<a:bind value="e.text" />
<textbox />
</row>
<row>
<label value="Event Type:" />
<radiogroup id="type">
<radio label="Duration Event"
checked="${e.duration}" />
<radio label="Not Duration Event"
checked="${!e.duration}" />
</radiogroup>
</row>
<row>
<label value="Description:" />
<a:bind value="e.description" />
<textbox rows="3" width="99%" />
</row>
<row>
<label value="Image url:" />
<a:bind value="e.imageUrl" />
<textbox />
</row>
<row>
<label value="Icon url:" />
<a:bind value="e.iconUrl" />
<textbox />
</row>
<row>
<label value="Link url:" />
<a:bind value="e.linkUrl" />
<textbox />
</row>
<row>
<label value="Color" />
<a:bind value="e.color" />
<textbox />
</row>
<row>
<label value="Text Color" />
<a:bind value="e.textColor" />
<textbox />
</row>
</rows>
</grid>
<hbox>
<button label="OK" onClick="update()" />
<button label="Cancle" onClick="cancle()" />
</hbox>
<zscript>
<![CDATA[
AnnotateDataBinder binder = new AnnotateDataBinder(eventwin);
binder.bindBean("e", e);
binder.loadAll();
void update() {
binder.saveAll();
if(type.getSelectedIndex()==0)
e.setDuration(true);
else
e.setDuration(false);
eventwin.setAttribute("OK",true);
eventwin.detach();
}
void cancle(){
eventwin.setAttribute("OK",false);
eventwin.detach();
}
]]>
</zscript>
</window>
Here is remove-event.zul
<window title="remove occur event window" width="300px"
xmlns:a="http://www.zkoss.org/2005/zk/annotation" id="removewin">
<zscript>
<![CDATA[
import java.util.*;
ArrayList events=arg.get("events");
]]>
</zscript>
<listbox id="eventList">
<listhead>
<listheader label="Text" width="40%" />
<listheader label="Start Date" width="30%" />
<listheader label="End Date" width="30%" />
</listhead>
<listitem forEach="">
<listcell label="" />
<listcell label="" />
<listcell label="" />
</listitem>
</listbox>
<hbox>
<button label="OK" onClick="ok()" />
<button label="Cancle" onClick="cancle()" />
</hbox>
<zscript>
<![CDATA[
void ok() {
int index=eventList.getSelectedIndex();
removewin.setAttribute("selected",index);
removewin.detach();
}
void cancle() {
removewin.setAttribute("selected",-1);
removewin.detach();
}
]]>
</zscript>
</window>
Filter and Highlight
Sometimes the user need to find what he wanted in a huge amount of information. By Filtering user can hide all events that don’t match. And sometimes the user need to highlight the events. User can use four colors to highlight events.
<button label="Filter and Highlight">
<attribute name="onClick">
<![CDATA[
Map params=new HashMap();
params.put("filter",filter);
params.put("highlight1",highlight[0]);
params.put("highlight2",highlight[1]);
params.put("highlight3",highlight[2]);
params.put("highlight4",highlight[3]);
Window w=(Window)Executions.createComponents("filter-highlight.zul", null, params);
w.doModal();
filter=(String)w.getAttribute("filter");
tl.performFiltering(filter);
highlight[0]=(String)w.getAttribute("highlight1");
highlight[1]=(String)w.getAttribute("highlight2");
highlight[2]=(String)w.getAttribute("highlight3");
highlight[3]=(String)w.getAttribute("highlight4");
tl.performHighlight(highlight);
]]>
</attribute>
</button>
<window title="remove occur event window" width="300px"
xmlns:a="http://www.zkoss.org/2005/zk/annotation" id="removewin">
<zscript>
<![CDATA[
import java.util.*;
ArrayList events=arg.get("events");
]]>
</zscript>
<listbox id="eventList">
<listhead>
<listheader label="Text" width="40%" />
<listheader label="Start Date" width="30%" />
<listheader label="End Date" width="30%" />
</listhead>
<listitem forEach="${events}">
<listcell label="${each.text}" />
<listcell label="${each.start}" />
<listcell label="${each.end}" />
</listitem>
</listbox>
<hbox>
<button label="OK" onClick="ok()" />
<button label="Cancle" onClick="cancle()" />
</hbox>
<zscript>
<![CDATA[
void ok() {
int index=eventList.getSelectedIndex();
removewin.setAttribute("selected",index);
removewin.detach();
}
void cancle() {
removewin.setAttribute("selected",-1);
removewin.detach();
}
]]>
</zscript>
</window>
Here is filter-highlight.zul:
<window title="new occur event window" width="300px" id="filterwin">
<vbox>
<hbox>
Filter :
<textbox id="filter" />
</hbox>
<hbox>
Highlight:
<vbox>
<label value="highlight1"
style="background-color:#FFFF00;" />
<textbox id="highlight1" />
<label value="highlight2"
style="background-color:#FFC000;" />
<textbox id="highlight2" />
<label value="highlight3" style="background-color:red;" />
<textbox id="highlight3" />
<label value="highlight4"
style="background-color:blue;" />
<textbox id="highlight4" />
</vbox>
</hbox>
<hbox>
<button label="Ok" onClick="update()" />
<button label="Clear" onClick="clear()" />
</hbox>
</vbox>
<zscript>
<![CDATA[
filter.value=arg.get("filter");
highlight1.value=arg.get("highlight1");
highlight2.value=arg.get("highlight2");
highlight3.value=arg.get("highlight3");
highlight4.value=arg.get("highlight4");
void update() {
filterwin.setAttribute("filter",filter.value);
filterwin.setAttribute("highlight1",highlight1.value);
filterwin.setAttribute("highlight2",highlight2.value);
filterwin.setAttribute("highlight3",highlight3.value);
filterwin.setAttribute("highlight4",highlight4.value);
filterwin.detach();
}
void clear(){
filter.value="";
highlight1.value="";
highlight2.value="";
highlight3.value="";
highlight4.value="";
}
]]>
</zscript>
</window>
Add and Remove Decorator
Decorator is different from Highlight feature. Decorator acts on Band and Highlight acts on the event of band. There are SpanHighlightDecorator and PointHighlightDecorator to decorate band. The developer can use addHighlightDecorator and removeHighlightDerotator to handle decorators. Here, I will show you how to use SpanHighlightDecorator.
<button label="Add SpanHighlightDecorator">
<attribute name="onClick">
<![CDATA[
Map params=new HashMap();
params.put("decorator",shd);
Window w=(Window)Executions.createComponents("decorator.zul", null, params);
w.doModal();
if(w.getAttribute("OK")){
b1.removeHighlightDecorator(shd);
b2.removeHighlightDecorator(shd);
b1.addHighlightDecorator(shd);
b2.addHighlightDecorator(shd);
}
]]>
</attribute>
</button>
<button label="Remove SpanHighlightDecorator">
<attribute name="onClick">
<![CDATA[
b1.removeHighlightDecorator(shd);
b2.removeHighlightDecorator(shd);
]]>
</attribute>
</button>
Decorator.zul
<window title="new occur event window" width="300px"
xmlns:a="http://www.zkoss.org/2005/zk/annotation" id="decoratorwin">
<zscript>
<![CDATA[
import org.zkforge.timeline.decorator.*;
SpanHighlightDecorator d=arg.get("decorator");
]]>
</zscript>
<grid>
<columns>
<column label="Type" />
<column label="Context" />
</columns>
<rows>
<row>
<label value="Start Date:" />
<a:bind value="d.startDate" />
<datebox />
</row>
<row>
<label value="End Date:" />
<a:bind value="d.endDate" />
<datebox />
</row>
<row>
<label value="Start Label:" />
<a:bind value="d.startLabel" />
<textbox />
</row>
<row>
<label value="End Label:" />
<a:bind value="d.endLabel" />
<textbox />
</row>
<row>
<label value="Opacity:" />
<a:bind value="d.opacity" />
<textbox />
</row>
<row>
<label value="Color" />
<a:bind value="d.color" />
<textbox />
</row>
</rows>
</grid>
<hbox>
<button label="OK" onClick="update()" />
<button label="Cancle" onClick="cancle()" />
</hbox>
<zscript>
<![CDATA[
AnnotateDataBinder binder = new AnnotateDataBinder(decoratorwin);
binder.bindBean("d", d);
binder.loadAll();
void update() {
binder.saveAll();
decoratorwin.setAttribute("OK",true);
decoratorwin.detach();
}
void cancle(){
decoratorwin.setAttribute("OK",false);
decoratorwin.detach();
}
]]>
</zscript>
</window>
Lazy-Load
If we load all data when application is running then it maybe cause performance problem. So Lazy-Load is a very important and useful feature for web application. Using lazy-load you should implement an EventListener interface first. Then call addEventListener method to bind EventListener to onScrollEvent.
BandScrollListener.java
public class BandScrollListener implements EventListener {
private ArrayList _events;
private Bandinfo _band;
private Map _addedEvents;
public BandScrollListener(ArrayList events, Bandinfo band) {
_events = events;
_band = band;
_addedEvents = new HashMap();
}
public boolean isAsap() {
// TODO Auto-generated method stub
return false;
}
public void onEvent(Event event) {
// TODO Auto-generated method stub
BandScrollEvent e = (BandScrollEvent) event;
int count = _events.size();
ArrayList temp = new ArrayList();
for (int i = 0; i < count; i++) {
OccurEvent evt = (OccurEvent) _events.get(i);
if (evt.getStart().compareTo(e.getMin()) > 0
&& evt.getStart().compareTo(e.getMax()) < 0
&& !_addedEvents.containsKey(evt.getId())) {
_addedEvents.put(evt.getId(), evt.getId());
temp.add(evt);
}
}
_band.addManyOccureEvents(temp);
}
}
In lazyload.zul I generate a timeline component dynamically and add an EventListener to it.
<window title="Timeline" width="100%" id="w">
<zscript>
<![CDATA[
import java.util.*;
import org.zkforge.timeline.*;
import org.zkforge.timeline.data.*;
import BandScrollListener;
ArrayList events=new ArrayList();
//for demonstrating lazy-load
for(int i=0;i<12;i++){
OccurEvent e=new OccurEvent();
Date d=new Date();
d.setYear(d.getYear()-1);
d.setMonth(i);
e.setStart(d);
//d.setTime(d.getTime()+i*100000);
//e.setEnd(d);
e.setText("lazy-load"+String.valueOf(i));
events.add(e);
}
for(int i=0;i<12;i++){
OccurEvent e=new OccurEvent();
Date d=new Date();
d.setMonth(i);
e.setStart(d);
//d.setTime(d.getTime()+i*100000);
//e.setEnd(d);
e.setText("lazy-load"+String.valueOf(i));
events.add(e);
}
//create timeline component
Timeline tl=new Timeline();
Bandinfo b1=new Bandinfo();
Bandinfo b2=new Bandinfo();
tl.setHeight("250px");
b1.setId("b1");
b1.setIntervalUnit("month");
b1.setWidth("70%");
b1.addEventListener("onBandScroll", new BandScrollListener(events,b1));
b2.setIntervalUnit("year");
b2.setWidth("30%");
b2.setSyncWith(b1.getId());
b2.setTrackHeight((float)0.5);
b2.setTrackGap((float)0.2);
b2.setShowEventText(false);
b2.addEventListener("onBandScroll", new BandScrollListener(events,b2));
tl.appendChild(b1);
tl.appendChild(b2);
w.appendChild(tl);
]]>
</zscript>
</window>
Summary
You can use Bandinfo.addOccurEvent and Bandinfo.removeOccurEvent to add or remove an OccurEvent from band dynamically. Use Timeline.performFiltering(String) to filter OccurEvent and use Timeline.performHighlight(String[]) to highlight OccurEvent. You can also use Bandinfo.addHighlightDecorator() to decrotate the band. I hope you like this component and you can give suggestions to help me to further improve it.
Download the example code here.
Gu Wei Xing is a software developer in NanTong of JiangSu province, China. He loves Java software development and Flash programming. He is also the host developer of the timeline project for ZK.forge.
Copyright © Gu Wei Xing. This article is licensed under GNU Free Documentation License. |