home *** CD-ROM | disk | FTP | other *** search
Java Source | 1997-09-02 | 23.6 KB | 851 lines |
- /************************************************************************************************
-
- Image map with pop-up text displays.
-
- <applet code="IMap.class" width=w height=h>
- <param name="mapimage" value="url" or "url,color">
- <param name="fgcolor" value="color">
- <param name="bgcolor" value="color">
- <param name="border" value="size,color">
- <param name="font" value="name,style,size">
- <param name="margins" value="n,m">
- <param name="outline" value="color">
- <param name="default" value="url" or "url,target">
- <param name="status" value="string">
- <param name="shape-1" value="rect,x1,y1,x2,y2" or "circle,x,y,r"
- or "ellipse,x,y,a,b" or "polygon,x1,y1,x2,y2,...,xn,yn">
- <param name="url-1" value="url" or "url,target">
- <param name="status-1" value="string">
- <param name="text-1-1" value="string" or "indent|string">
- <param name="text-1-2" value="string" or "indent|string">
- <param name="text-1-3" value="string" or "indent|string">
- ...
- <param name="shape-n" value="rect,x1,y1,x2,y2" or "circle,x,y,r"
- or "ellipse,x,y,a,b" or "polygon,x1,y1,x2,y2,...,xn,yn">
- <param name="url-n" value="url" or "url,target">
- <param name="status-n" value="string">
- <param name="text-n-1" value="string" or "indent|string">
- <param name="text-n-2" value="string" or "indent|string">
- <param name="text-n-3" value="string" or "indent|string">
- ...
- </applet>
-
- ************************************************************************************************/
-
- import java.awt.*;
- import java.awt.image.*;
- import java.net.*;
- import java.util.*;
- import java.applet.Applet;
-
- /************************************************************************************************
- 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.
-
- // Constructors:
-
- // Create an area of the appropriate shape.
-
- public IMapArea(Rectangle rect) {
-
- this.shape = RECT;
- this.rect = rect;
- }
-
- public IMapArea(int x, int y, int a, int b) {
-
- this.shape = ELLIPSE;
- this.x = x;
- this.y = y;
- this.a = Math.abs(a);
- this.b = Math.abs(b);
- }
-
- public IMapArea(Polygon poly) {
-
- this.shape = POLY;
- this.poly = poly;
- }
-
- // Methods:
-
- // Determine the area shape.
-
- public boolean isRect() {
-
- if (this.shape == RECT)
- return(true);
-
- return(false);
- }
-
- public boolean isEllipse() {
-
- if (this.shape == ELLIPSE)
- return(true);
-
- return(false);
- }
-
- public boolean isPoly() {
-
- if (this.shape == POLY)
- return(true);
-
- return(false);
- }
-
- // Return the area as a shape object with the appropriate coordinates, useful for drawing.
-
- public Rectangle getRect() {
-
- if (this.isRect())
- return(this.rect);
-
- return(new Rectangle());
- }
-
- public Rectangle getEllipse() {
-
- if (this.isEllipse())
- return(new Rectangle(this.x - this.a, this.y - this.b, this.a * 2, this.b * 2));
-
- return(new Rectangle());
- }
-
- public Polygon getPoly() {
-
- if (this.isPoly())
- return(this.poly);
-
- return(new Polygon());
- }
-
- // 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.
-
- public void addText(int n, String s) {
-
- this.indent.addElement(new Integer(n));
- this.text.addElement(s);
- this.count++;
- }
-
- // Get a line of text.
-
- public String getText(int i) {
-
- 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;
-
- Dimension offDimension; // Off-screen graphic for drawing.
- Image offImage;
- Graphics offGraphics;
-
- // Applet information.
-
- public String getAppletInfo() {
-
- return("IMap version 1.4\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.4, 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.
-
- activeArea = -1;
- getAppletContext().showStatus("");
- repaint();
- return true;
- }
-
- public boolean mouseMove(Event e, int x, int y) {
-
- int last;
- int i;
-
- // Save the currently active area.
-
- last = activeArea;
-
- // If the mouse is over a area, mark it as active. (Go backwards thru the list to match the
- // behavior of image maps when areas overlap.)
-
- activeArea = -1;
- for (i = areas.size() - 1; i >= 0; i--) {
- area = (IMapArea) areas.elementAt(i);
- if (area.inside(x, y))
- activeArea = i;
- }
-
- // Update the display only if the active area has changed (this will save some processor
- // cycles).
-
- if (activeArea != last) {
- if (activeArea >= 0) {
- area = (IMapArea) areas.elementAt(activeArea);
- if (area.status != null)
- getAppletContext().showStatus(area.status);
- else if (area.url != null)
- getAppletContext().showStatus(area.url.toString());
- else
- getAppletContext().showStatus("");
- }
- repaint();
- }
-
- // When no area is active, show the default status window message.
-
- if (activeArea < 0) {
- if (status != null)
- getAppletContext().showStatus(status);
- else if (defaultUrl != null)
- getAppletContext().showStatus(defaultUrl.toString());
- else
- getAppletContext().showStatus("");
- }
-
- return true;
- }
-
- public boolean mouseDown(Event e, int x, int y) {
-
- // If there is currently an active area with a URL, link to it.
-
- if (activeArea >= 0) {
- area = (IMapArea) areas.elementAt(activeArea);
- if (area.url != null)
- if (area.target != null)
- getAppletContext().showDocument(area.url, area.target);
- else
- getAppletContext().showDocument(area.url);
- }
-
- // Otherwise, if a defaut URL was specified, link to it.
-
- else if (defaultUrl != null) {
- if (target != null)
- getAppletContext().showDocument(defaultUrl, target);
- else
- getAppletContext().showDocument(defaultUrl);
- }
-
- // No URL to link to, just return.
-
- return true;
- }
-
- public void paint(Graphics g) {
-
- update(g);
- }
-
- public void update(Graphics g) {
-
- Dimension d = size();
- int x, y;
- int i, j;
- int n;
- String s;
- Rectangle rect;
- Polygon poly;
-
- // Create the offscreen graphics context, if no good one exists.
-
- if (offGraphics == null || d.width != offDimension.width || d.height != offDimension.height) {
- offDimension = d;
- offImage = createImage(d.width, d.height);
- offGraphics = offImage.getGraphics();
- }
-
- // If the image map has finished loading, fill the canvas with the background color and draw
- // the map image over it.
-
- if ((checkImage(mapImage, this) & ImageObserver.ALLBITS) == ImageObserver.ALLBITS) {
- offGraphics.setColor(pgColor);
- offGraphics.fillRect(0, 0, d.width, d.height);
- offGraphics.drawImage(mapImage, 0, 0, this);
- }
-
- // Otherwise, put up a message and return.
-
- else {
- offGraphics.setColor(bgColor);
- offGraphics.fillRect(0, 0, d.width, d.height);
- offGraphics.setFont(font);
- offGraphics.setColor(fgColor);
- offGraphics.drawString("Loading image...", xAdvance, yHeight + yAscent);
- g.drawImage(offImage, 0, 0, this);
- return;
- }
-
- // If there is a currently active area, process it.
-
- if (activeArea >= 0) {
- area = (IMapArea) areas.elementAt(activeArea);
- rect = area.getBoundingBox();
-
- // Draw the outline of the area if the outline flag is set.
-
- if (olFlag) {
- offGraphics.setColor(olColor);
- if (area.isRect()) {
- rect = area.getRect();
- offGraphics.drawRect(rect.x, rect.y, rect.width, rect.height);
- }
- else if (area.isEllipse()) {
- rect = area.getEllipse();
- offGraphics.drawOval(rect.x, rect.y, rect.width, rect.height);
- }
- else if (area.isPoly()) {
- poly = area.getPoly();
- offGraphics.drawPolygon(poly);
- n = poly.npoints - 1;
- offGraphics.drawLine(poly.xpoints[n], poly.ypoints[n], poly.xpoints[0], poly.ypoints[0]);
- }
- }
-
- // Draw the pop-up text box for the active area if there is any text.
-
- if (area.getCount() > 0) {
-
- // Determine a starting position for the text box. An attempt is made to keep it from
- // overlaying the area if possible.
-
- x = 0; y = 0;
-
- // Get the x-coord for the text box.
-
- if ((rect.x + rect.width) / 2 < d.width / 2)
- x = rect.x + rect.width + xAdvance;
- else
- x = Math.max(0,rect.x - area.width - xAdvance);
- if (x + area.width > d.width)
- x = Math.max(0, d.width - area.width - xAdvance);
-
- // Get the y-coord for the box.
-
- if (rect.intersects(new Rectangle(x,rect.y, area.width, rect.height)))
- if (d.height - (rect.y + rect.height + yHeight) >= area.height)
- y = rect.y + rect.height + yHeight;
- else
- y = rect.y - area.height - yHeight;
- else if (rect.y + rect.height / 2 < d.height / 2)
- y = rect.y + rect.height / 2;
- else
- y = Math.max(0,rect.y + rect.height / 2 - area.height);
- if (y + area.height > d.height)
- y = Math.max(0, d.height - area.height - yHeight);
-
- // Draw the pop-up box and border.
-
- offGraphics.setColor(bdColor);
- offGraphics.fillRect(x, y, area.width, area.height);
- offGraphics.setColor(bgColor);
- offGraphics.fillRect(x + bdSize, y + bdSize, area.width - 2 * bdSize, area.height - 2 * bdSize);
-
- // Add the text.
-
- 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);
- }
- }
- }
-
- // Paint the image onto the screen.
-
- g.drawImage(offImage, 0, 0, this);
- }
- }
-