/************************************************************************************************
The IMapArea class defines the area shape, position and text for the the pop-up box.
************************************************************************************************/
class IMapArea {
// Constants:
private final static int RECT = 1; // Shape types.
private final static int ELLIPSE = 2;
private final static int POLY = 3;
// Fields:
private int shape; // This area's shape, one of:
private Rectangle rect; // rectangle
private int x, y, a, b; // ellipse
private Polygon poly; // polygon
public URL url = null; // URL to link to when clicked.
public String target = null; // Target window.
public String status = null; // Status window message.
private Vector text = new Vector(10, 5); // Text line array.
private Vector indent = new Vector(10, 5); // Indent for each text line.
private int count = 0; // Number of text lines.
public int width = 0; // Width of text box.
public int height = 0; // Height of text box.
// Find the smallest rectangle that contains the shape.
public Rectangle getBoundingBox() {
Rectangle rect;
rect = new Rectangle();
if (this.isRect())
rect = this.rect;
if (this.isEllipse())
rect = this.getEllipse();
if (this.isPoly())
rect = this.poly.getBoundingBox();
return(rect);
}
// Set the URL to link to.
public void setURL(URL url) {
this.url = url;
}
// Set the URL and target frame or window to link to.
public void setURL(URL url, String target) {
this.url = url;
this.target = target;
}
// Set the message to display in the status window when this link is active.
public void setStatusMsg(String msg) {
this.status = msg;
}
// Determine if a given point is inside the area.
public boolean inside(int x, int y) {
double v;
if (this.isRect())
return(this.rect.inside(x, y));
if (this.isEllipse()) {
x -= this.x;
y -= this.y;
if (Math.abs(x) > this.a || Math.abs(y) > b)
return(false);
v = (int) ((double) this.b * Math.sqrt(1.0 - (double) (x * x) / (double) (this.a * this.a)));
if (Math.abs(y) <= v)
return(true);
}
if (this.isPoly())
return(this.poly.inside(x, y));
return(false);
}
// Add a line of text with the specified indentation.
if (i >= 0 && i < this.count)
return((String) this.text.elementAt(i));
else
return((String) null);
}
// Get amount of indentation for a line of text.
public int getIndent(int i) {
if (i >= 0 && i < this.count)
return(Integer.parseInt(this.indent.elementAt(i).toString()));
else
return(0);
}
// Get number of text lines.
public int getCount() {
return(this.count);
}
}
/************************************************************************************************
Main applet code.
************************************************************************************************/
public class IMap extends Applet {
// Parameters and defaults.
Image mapImage = null; // Map image.
Color pgColor = Color.white; // Applet background color.
Color fgColor = Color.black; // Text color.
Color bgColor = Color.white; // Text box background color.
int bdSize = 0; // Text box border size.
Color bdColor; // Text box border color.
String fontName = "Dialog"; // Text font.
int fontStyle = Font.PLAIN; // Text font style.
int fontSize = 12; // Text font size.
int hrznMargin = 10; // Horizontal margin for text.
int vertMargin = 10; // Verticle margin for text.
boolean olFlag = false; // Area outline flag.
Color olColor = Color.black; // Area outline color.
URL defaultUrl = null; // Default image map link.
String target = null; // Target window or frame for the default link.
String status = null; // Status window message for the default link.
// Global variables.
Vector areas = new Vector(10, 5); // A list of all the defined areas.
IMapArea area; // The currently active area.
int activeArea = -1;
Font font; // Font size values.
int xAdvance;
int yAscent;
int yHeight;
return("IMap version 1.5\n\nCopyright 1997 by Mike Hall");
}
public void init() {
String s, t, u;
StringTokenizer st;
URL url;
int i, j;
Graphics g;
FontMetrics fm;
int n;
// Take credit.
System.out.println("IMap version 1.5, Copyright 1997 by Mike Hall.");
// Get the map image and optional background color and start loading the image.
try {
s = getParameter("mapimage");
if (s != null) {
st = new StringTokenizer(s, ",");
mapImage = getImage(new URL(getDocumentBase(), st.nextToken()));
prepareImage(mapImage, this);
if (st.hasMoreTokens())
pgColor = getColorParm(st.nextToken());
}
}
catch (Exception e) {}
// Get the pop-up text box colors.
try {
s = getParameter("fgcolor");
if (s != null)
fgColor = getColorParm(s);
}
catch (Exception e) {}
bdColor = fgColor;
try {
s = getParameter("bgcolor");
if (s != null)
bgColor = getColorParm(s);
}
catch (Exception e) {}
// Get the pop-up text box border parameters.
try {
s = getParameter("border");
if (s != null) {
st = new StringTokenizer(s, ",");
if ((n = Integer.parseInt(st.nextToken())) > 0)
bdSize = n;
if (st.hasMoreTokens())
bdColor = getColorParm(st.nextToken());
}
}
catch (Exception e) {}
// Get the text box font.
try {
s = getParameter("font");
// Font name.
st = new StringTokenizer(s, ",");
t = st.nextToken();
if (t.equalsIgnoreCase("Courier"))
fontName = "Courier";
else if (t.equalsIgnoreCase("Dialog"))
fontName = "Dialog";
else if (t.equalsIgnoreCase("Helvetica"))
fontName = "Helvetica";
else if (t.equalsIgnoreCase("Symbol"))
fontName = "Symbol";
else if (t.equalsIgnoreCase("TimesRoman"))
fontName = "TimesRoman";
// Font style.
t = st.nextToken();
if (t.equalsIgnoreCase("plain"))
fontStyle = Font.PLAIN;
else if (t.equalsIgnoreCase("bold"))
fontStyle = Font.BOLD;
else if (t.equalsIgnoreCase("italic"))
fontStyle = Font.ITALIC;
else if (t.equalsIgnoreCase("boldItalic"))
fontStyle = Font.BOLD + Font.ITALIC;
// Font size.
t = st.nextToken();
if ((n = Integer.parseInt(t)) > 0)
fontSize = n;
}
catch (Exception e) {}
// Get the pop-up text box margins.
try {
s = getParameter("margins");
if (s != null) {
st = new StringTokenizer(s, ",");
if ((n = Integer.parseInt(st.nextToken())) > 0)
hrznMargin = n;
if ((n = Integer.parseInt(st.nextToken())) > 0)
vertMargin = n;
}
}
catch (Exception e) {}
// Get the area outline color.
try {
s = getParameter("outline");
if (s != null) {
olColor = getColorParm(s);
olFlag = true;
}
}
catch (Exception e) {}
// Get the default URL, target and status window message for the image map.
try {
s = getParameter("default");
st = new StringTokenizer(s, ",");
t = st.nextToken();
try {
url = new URL(getDocumentBase(), t);
if (st.hasMoreTokens()) {
t = st.nextToken();
target = t;
}
defaultUrl = url;
}
catch (MalformedURLException e) {}
}
catch (Exception e) {}
try {
s = getParameter("status");
if (s != null)
status = s;
}
catch (Exception e) {}
// Get data for each image map area.
s = null;
i = 1;
do {
try {
s = getParameter("shape-" + i);
if (s != null) {
getShape(s);
// Get the URL, target and status window message.
try {
t = getParameter("url-" + i);
st = new StringTokenizer(t, ",");
u = st.nextToken();
try {
url = new URL(getDocumentBase(), u);
if (st.hasMoreTokens()) {
u = st.nextToken();
area.setURL(url, u);
}
else
area.setURL(url);
}
catch (MalformedURLException e) {}
}
catch (Exception e) {}
try {
t = getParameter("status-" + i);
if (t != null)
area.setStatusMsg(t);
}
catch (Exception e) {}
// Get text to display in the pop-up text box for this area.
t = null;
j = 1;
do {
try {
t = getParameter("text-" + i + "-" + j);
if (t != null) {
st = new StringTokenizer(t, "|");
if (st.countTokens() > 1) {
n = Integer.parseInt(st.nextToken());
u = st.nextToken();
}
else {
n = 0;
u = t;
}
area.addText(n, u);
}
}
catch (Exception e) {}
j++;
} while (t != null);
// Add the area to the list.
areas.addElement(area);
}
}
catch (Exception e) {}
i++;
} while (s != null);
// Trim the areas list to reclaim unused space.
areas.trimToSize();
// Set size values based on the font.
g = getGraphics();
font = g.getFont();
g.setFont(font = new Font(fontName, fontStyle, fontSize));
fm = g.getFontMetrics();
xAdvance = fm.getMaxAdvance();
yAscent = fm.getMaxAscent();
yHeight = fm.getHeight();
// Calculate the size of the pop-up text box for each area.
for (i = 0; i < areas.size(); i++) {
area = (IMapArea) areas.elementAt(i);
for (j = 0; j < area.getCount(); j++) {
s = area.getText(j);
n = area.getIndent(j) * xAdvance + fm.stringWidth(s);
if (n > area.width)
area.width = n;
}
area.width += 2 * hrznMargin;
area.height = area.getCount() * yHeight + 2 * vertMargin;
}
}
private Color getColorParm(String s) {
int r, g, b;
// Check if a pre-defined color is specified.
if (s.equalsIgnoreCase("black"))
return(Color.black);
if (s.equalsIgnoreCase("blue"))
return(Color.blue);
if (s.equalsIgnoreCase("cyan"))
return(Color.cyan);
if (s.equalsIgnoreCase("darkGray"))
return(Color.darkGray);
if (s.equalsIgnoreCase("gray"))
return(Color.gray);
if (s.equalsIgnoreCase("green"))
return(Color.green);
if (s.equalsIgnoreCase("lightGray"))
return(Color.lightGray);
if (s.equalsIgnoreCase("magenta"))
return(Color.magenta);
if (s.equalsIgnoreCase("orange"))
return(Color.orange);
if (s.equalsIgnoreCase("pink"))
return(Color.pink);
if (s.equalsIgnoreCase("red"))
return(Color.red);
if (s.equalsIgnoreCase("white"))
return(Color.white);
if (s.equalsIgnoreCase("yellow"))
return(Color.yellow);
// If the color is specified in HTML format, build it from the red, green and blue values.
if (s.length() == 7 && s.charAt(0) == '#') {
r = Integer.parseInt(s.substring(1,3),16);
g = Integer.parseInt(s.substring(3,5),16);
b = Integer.parseInt(s.substring(5,7),16);
return(new Color(r, g, b));
}
// If we can't figure it out, default to black.
return(Color.black);
}
private void getShape(String s) {
StringTokenizer st;
String t;
int x1, y1, x2, y2;
int x, y, a, b;
Polygon poly;
// Set the area depending on the supplied shape parameters. (Note that a circle is a special
// case of an ellipse where a = b.)
st = new StringTokenizer(s, ",");
t = st.nextToken();
if (t.equalsIgnoreCase("rect")) {
x1 = Integer.parseInt(st.nextToken());
y1 = Integer.parseInt(st.nextToken());
x2 = Integer.parseInt(st.nextToken());
y2 = Integer.parseInt(st.nextToken());
area = new IMapArea(new Rectangle(x1, y1, x2 - x1, y2 - y1));
return;
}
if (t.equalsIgnoreCase("circle")) {
x = Integer.parseInt(st.nextToken());
y = Integer.parseInt(st.nextToken());
a = Integer.parseInt(st.nextToken());
area = new IMapArea(x, y, a, a);
return;
}
if (t.equalsIgnoreCase("ellipse")) {
x = Integer.parseInt(st.nextToken());
y = Integer.parseInt(st.nextToken());
a = Integer.parseInt(st.nextToken());
b = Integer.parseInt(st.nextToken());
area = new IMapArea(x, y, a, b);
return;
}
if (t.equalsIgnoreCase("poly")) {
poly = new Polygon();
while (st.hasMoreTokens()) {
x = Integer.parseInt(st.nextToken());
y = Integer.parseInt(st.nextToken());
poly.addPoint(x, y);
}
area = new IMapArea(poly);
}
}
public boolean mouseExit(Event e, int x, int y) {
// Deactivate any currently active area and clear the status window.
offGraphics.setFont(font);
offGraphics.setColor(fgColor);
for (i = 0; i < area.getCount(); i++) {
j = 0;
s = area.getText(i);
n = area.getIndent(i);
offGraphics.drawString(s, x + hrznMargin + xAdvance * n, y + vertMargin + i * yHeight + yAscent);
}
}
}