I used to implement clickable chart by image tag and usemap tag in my old web project, when i migrate to vaadin platform, i couldn’t find a component supoorts both image and usemap, so i made a add-on widget, hope it could be useful to someone else who have a same problem as me
Vaadin Component:
@com.vaadin.ui.ClientWidget(com.fab.yms.web.common.client.ui.VUsemapImage.class)
public class UsemapImage extends AbstractComponent
{
/**
*
*/
private static final long serialVersionUID = -6768105755082174490L;
private Resource image;
private String usemap;
public void setUsemapImage(Resource image, String usemap)
{
if(image != null)
{
String mt = image.getMIMEType();
if ((mt.substring(0, mt.indexOf("/")).equalsIgnoreCase("image")))
{
this.image = image;
this.usemap = usemap;
requestRepaint();
}
else
{
throw new IllegalArgumentException(mt + " is not a valid image type");
}
}
}
@Override
public void paintContent(PaintTarget target) throws PaintException
{
super.paintContent(target);
if (image != null)
{
target.addAttribute(VUsemapImage.ATTRIBUTE_IMAGE, image);
if (usemap != null)
target.addAttribute(VUsemapImage.ATTRIBUTE_USEMAP, usemap);
}
}
/**
* Receive and handle events and other variable changes from the client.
*
* {@inheritDoc}
*/
@Override
public void changeVariables(Object source, Map<String, Object> variables)
{
super.changeVariables(source, variables);
if (variables.containsKey(VUsemapImage.EVENT_ID_MOUSE_UP))
{
Object obj = variables.get(VUsemapImage.EVENT_ID_MOUSE_UP);
if(obj instanceof Object[])
{
Object[] params = (Object[]
)obj;
AreaClickEvent event = new AreaClickEvent(this, params);
fireEvent(event);
requestRepaint();
}
}
}
public interface AreaClickListener extends ComponentEventListener
{
public static final Method ONCLICK_METHOD = ReflectTools.findMethod(
AreaClickListener.class, "onClick", AreaClickEvent.class);
public void onClick(AreaClickEvent event);
}
public void addListener(AreaClickListener listener)
{
addListener(AreaClickEvent.class, listener, AreaClickListener.ONCLICK_METHOD);
}
public void removeListener(AreaClickListener listener)
{
removeListener(AreaClickEvent.class, listener, AreaClickListener.ONCLICK_METHOD);
}
public class AreaClickEvent extends Component.Event
{
/**
*
*/
private static final long serialVersionUID = 8754823991334501952L;
private int x, y;
private String mouseButton, id, title, alt, shape, coords, href, target;//, data;
public AreaClickEvent(Component source, Object[] area)
{
super(source);
x = (Integer)area[VUsemapImage.IDX_MOUSE_CLICK_X]
;
y = (Integer)area[VUsemapImage.IDX_MOUSE_CLICK_Y]
;
mouseButton = (String)area[VUsemapImage.IDX_MOUSE_BUTTONG]
;
id = (String)area[VUsemapImage.IDX_ID]
;
title = (String)area[VUsemapImage.IDX_TITLE]
;
alt = (String)area[VUsemapImage.IDX_ALT]
;
shape = (String)area[VUsemapImage.IDX_SHAPE]
;
coords = (String)area[VUsemapImage.IDX_COORDS]
;
href = (String)area[VUsemapImage.IDX_HREF]
;
target = (String)area[VUsemapImage.IDX_TARGET]
;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public String getMouseButton()
{
return mouseButton;
}
public String getId()
{
return id;
}
public String getTitle()
{
return title;
}
public String getAlt()
{
return alt;
}
public String getShape()
{
return shape;
}
public String getCoords()
{
return coords;
}
public String getHref()
{
return href;
}
public String getTarget()
{
return target;
}
}
}
GWT component
public class VUsemapImage extends HTML implements Paintable, MouseUpHandler
{
public static final String ATTRIBUTE_IMAGE = “image”;
public static final String ATTRIBUTE_USEMAP = “usemap”;
public static final String EVENT_ID_MOUSE_UP = "click";
public static final int IDX_MOUSE_BUTTONG = 0;
public static final int IDX_MOUSE_CLICK_X = 1;
public static final int IDX_MOUSE_CLICK_Y = 2;
public static final int IDX_ID = 3;
public static final int IDX_TITLE = 4;
public static final int IDX_ALT = 5;
public static final int IDX_SHAPE = 6;
public static final int IDX_COORDS = 7;
public static final int IDX_HREF = 8;
public static final int IDX_TARGET = 9;
/** Set the CSS class name to allow styling. */
public static final String CLASSNAME = "v-usemapimage";
/** The client side widget identifier */
protected String paintableId;
/** Reference to the server connection object. */
protected ApplicationConnection client;
protected NodeList<AreaElement> areas;
protected AreaElement getArea(int x, int y)
{
if (areas == null || areas.getLength() == 0)
return null;
AreaElement area = null;
for (int i = 0; i < areas.getLength(); i++)
{
AreaElement a = areas.getItem(i);
if (XYinArea(x, y, a))
{
area = a;
break;
}
}
return area;
}
protected boolean XYinArea(int x, int y, AreaElement area)
{
String shape = area.getShape();
List<Double> coords = getCoordsList(area.getCoords());
boolean result = false;
if (shape.compareToIgnoreCase("rect") == 0)
{
result = XYinRect(x, y, coords);
} else if (shape.compareToIgnoreCase("circle") == 0)
{
result = XYinCircle(x, y, coords);
} else if (shape.compareToIgnoreCase("poly") == 0)
{
result = XYinPoly(x, y, coords);
}
return result;
}
protected List<Double> getCoordsList(String coords)
{
List<Double> lst = new LinkedList<Double>();
String[] ss = coords.split(",");
if (ss == null)
return lst;
for (String s : ss)
{
lst.add(Double.valueOf(s));
}
return lst;
}
protected boolean XYinRect(int x, int y, List<Double> lstCoord)
{
int x1 = lstCoord.get(0).intValue();
int y1 = lstCoord.get(1).intValue();
int x2 = lstCoord.get(2).intValue();
int y2 = lstCoord.get(3).intValue();
if (x >= x1 && x <= x2 && y >= y1 && y <= y2)
return true;
else
return false;
}
protected boolean XYinCircle(int x, int y, List<Double> lstCoord)
{
int x1 = lstCoord.get(0).intValue();
int y1 = lstCoord.get(1).intValue();
int r = lstCoord.get(2).intValue();
if (((x - x1) * (x - x1) + (y - y1) * (y - y1)) <= r * r)
return true;
else
return false;
}
protected boolean XYinPoly(int x, int y, List<Double> lstCoord)
{
double x1 = lstCoord.get(0);
double y1 = lstCoord.get(1);
double xn = lstCoord.get(lstCoord.size() - 2);
double yn = lstCoord.get(lstCoord.size() - 1);
if (x1 != xn || y1 != yn)
{
lstCoord.add(x1);
lstCoord.add(y1);
}
int polySides = lstCoord.size() / 2;
double[] polyX = new double[polySides]
, polyY = new double[polySides]
;
for (int i = 0; i < lstCoord.size(); i++)
{
double v = lstCoord.get(i);
if (i % 2 == 0)
polyX[i / 2]
= v;
else
polyY[i / 2]
= v;
}
return pointInPolygon(polySides, polyX, polyY, x, y);
}
/**
* from http://alienryderflex.com/polygon/
*
* @param polySides
* how many corners the polygon has
* @param polyX
* horizontal coordinates of corners
* @param polyY
* vertical coordinates of corners
* @param x
* point to be tested
* @param y
* point to be tested
* @return true if the point x,y is inside the polygon
*/
protected boolean pointInPolygon(int polySides, double polyX[],
double polyY[], double x, double y)
{
int i, j = polySides - 1;
boolean oddNodes = false;
for (i = 0; i < polySides; i++)
{
if (polyY[i]
< y && polyY[j]
= y || polyY[j]
< y && polyY[i]
= y)
{
if (polyX[i]
- (y - polyY[i]
) / (polyY[j]
-
polyY[i]
)
* (polyX[j] -
polyX[i]
) < x)
{
oddNodes = !oddNodes;
}
}
j = i;
}return oddNodes;
}
/**
-
The constructor should first call super() to initialize the component and
-
then handle any initialization relevant to Vaadin.
*/
public VUsemapImage()
{
super();
setElement(Document.get().createDivElement());// This method call of the Paintable interface sets the component
// style name in DOM tree
setStyleName(CLASSNAME);// Tell GWT we are interested in receiving click events
// sinkEvents(Event.ONCLICK);
// Add a handler for the click events (this is similar to
// FocusWidget.addClickHandler())
// addDomHandler(this, ClickEvent.getType());sinkEvents(Event.ONMOUSEUP);
addDomHandler(this, MouseUpEvent.getType());
}
/**
-
Called whenever an update is received from the server
*/
public void updateFromUIDL(UIDL uidl, ApplicationConnection client)
{
if (client.updateComponent(this, uidl, true))
return;this.client = client;
// Save the client side identifier (paintable id) for the widget
paintableId = uidl.getId();// clickEventHandler.handleEventHandlerRegistration(client);
if (uidl.hasAttribute(ATTRIBUTE_IMAGE))
{
areas = null;
//setHTML(“”);String url = client.translateVaadinUri(uidl.getStringAttribute(ATTRIBUTE_IMAGE)); if (url == null) url = ""; Element elm_img = null, elm_map = null; NodeList<Node> nodes = getElement().getChildNodes(); if (nodes != null && nodes.getLength() > 0 ) { for(int i=0; i < nodes.getLength(); i++) { Node n = nodes.getItem(i); if (n.getNodeType() != Node.ELEMENT_NODE) continue; Element e = (Element) n; if (e.getTagName().equalsIgnoreCase("IMG")) { elm_img = e; } else if(e.getTagName().equalsIgnoreCase("MAP")) { elm_map = e; } } } boolean created_img = false; if(elm_img == null) { elm_img = DOM.createImg(); created_img = true; client.addPngFix(elm_img); DOM.sinkEvents(elm_img, Event.ONLOAD); } // Set attributes Style style = elm_img.getStyle(); String w = uidl.getStringAttribute("width"); if (w != null) { style.setProperty("width", w); } else { style.setProperty("width", ""); } String h = uidl.getStringAttribute("height"); if (h != null) { style.setProperty("height", h); } else { style.setProperty("height", ""); } DOM.setElementProperty(elm_img, "src", url); if (uidl.hasAttribute(ATTRIBUTE_USEMAP)) { String usemap = uidl.getStringAttribute(ATTRIBUTE_USEMAP); if(usemap!=null && usemap.length()>0) { boolean created_map = false; if(elm_map == null) { elm_map = DOM.createElement("map"); created_map = true; } elm_map.setInnerHTML(usemap); areas = MapElement.as(elm_map).getAreas(); String filename = url.substring(url.lastIndexOf('/')+1); if(filename!=null && filename.length()>0) { /** * TODO, GWT's problem, see * http://code.google.com/p/google-web-toolkit/issues/detail?id=3041 */ DOM.setElementProperty(elm_img, "useMap", "#" + filename); DOM.setElementProperty(elm_map, "name", filename); if (created_map) { getElement().appendChild(elm_map); } } } } if (created_img) { getElement().appendChild(elm_img); } /* * Sink tooltip events so tooltip is displayed when hovering the * image. */ sinkEvents(VTooltip.TOOLTIP_EVENTS);
}
}
@Override
public void onMouseUp(MouseUpEvent event)
{
String b = null;
switch (event.getNativeButton())
{
case NativeEvent.BUTTON_LEFT:
b = “left”;
break;
case NativeEvent.BUTTON_MIDDLE:
b = “middle”;
break;
case NativeEvent.BUTTON_RIGHT:
b = “right”;
break;
default:
b = “unknown”;
}int x = event.getX(), y = event.getY(); Object[] map = new Object[10]
-
;
map[IDX_MOUSE_BUTTONG]
= b;
map[IDX_MOUSE_CLICK_X]
= x;
map[IDX_MOUSE_CLICK_Y]
= y;
AreaElement area = getArea(x, y);
if (area != null)
{
map[IDX_ID]
= area.getId();
map[IDX_TITLE]
= area.getTitle();
map[IDX_ALT]
= area.getAlt();
map[IDX_SHAPE]
= area.getShape();
map[IDX_COORDS]
= area.getCoords();
map[IDX_HREF]
= area.getHref();
map[IDX_TARGET]
= area.getTarget();
}
client.updateVariable(paintableId, EVENT_ID_MOUSE_UP, map, true);
}
}