[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Graph.class
Hi Dan
> Sounds good -- can't see it in Lynx browser so won't be able to check it
> out till next week. Can I see your tweaked code?
Sure, I'll attach those two files (RDFGraph.java and Node.java) here.
Janne
--
Janne Saarela | Visiting scientist
Email: jsaarela@w3.org | World Wide Web Consortium http://www.w3.org/
/**
* Node class holds corresponding graphical positions
*/
import java.awt.*;
import java.util.Vector;
public class Node
{
private String m_sName = null;
private Point m_point = null;
private Vector m_nextNodes = new Vector();
private Color m_color = Color.black;
static public boolean GENIDS = false;
static public boolean SHORTNAMES = true;
public static final Color DEFAULT_COLOR = Color.black;
public static final Color SELECTED_COLOR = Color.blue;
double dx;
double dy;
boolean fixed;
Node (String sName) {
m_sName = sName;
m_point = new Point (0,0);
}
Node (String sName, Point p) {
m_sName = sName;
m_point = p;
}
public void setPoint (int x, int y) {
m_point.move (x, y);
}
public void setPoint (Point p) {
m_point = p;
}
public void addNextNode (Node n) {
m_nextNodes.addElement (n);
}
public Vector nextNodes () {
return m_nextNodes;
}
public String visualName() {
if (!GENIDS &&
m_sName.startsWith ("genid"))
return new String ();
if (SHORTNAMES) {
int iHashIndex = m_sName.lastIndexOf('#');
if (iHashIndex > -1)
return m_sName.substring (iHashIndex+1);
else
return m_sName;
} else {
return m_sName;
}
}
public String name() {
return m_sName;
}
public void name(String sName) {
m_sName = sName;
}
public int x () {
return m_point.x;
}
public void x (int x) {
m_point.x = x;
}
public int y () {
return m_point.y;
}
public void y (int y) {
m_point.y = y;
}
public Color color () {
return m_color;
}
public void setColor (Color c) {
m_color = c;
}
public double distance (Point p) {
int dx = m_point.x-p.x;
int dy = m_point.y-p.y;
return dx*dx + dy*dy;
}
}
/*
* Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
* @modified 96/04/24 Jim Hagen : changed stressColor
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
* without fee is hereby granted.
* Please refer to the file http://java.sun.com/copy_trademarks.html
* for further important copyright and trademark information and to
* http://java.sun.com/licensing.html for further important licensing
* information for the Java (tm) Technology.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*
* THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
* CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
* PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
* NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
* SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
* SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
* PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). SUN
* SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
* HIGH RISK ACTIVITIES.
*/
import java.io.*;
import java.util.*;
import java.awt.*;
import java.applet.Applet;
class Edge {
int from;
int to;
String lbl;
double len;
}
class GraphPanel extends Panel implements Runnable {
RDFGraph graph;
int nnodes;
Node nodes[] = new Node[500];
int nedges;
Edge edges[] = new Edge[100];
Thread relaxer;
boolean genids = false;
boolean shortnames = true;
GraphPanel(RDFGraph graph) {
this.graph = graph;
}
int findNode(String lbl) {
for (int i = 0 ; i < nnodes ; i++) {
String sName = nodes[i].name();
if (sName != null && sName.equals(lbl)) {
return i;
}
}
return addNode(lbl);
}
int addNode(String lbl) {
Node n = new Node(lbl);
n.x(10 + (int)(380*Math.random()));
n.y(10 + (int)(380*Math.random()));
nodes[nnodes] = n;
return nnodes++;
}
void addEdge(String lbl, String from, String to, int len) {
Edge e = new Edge();
e.lbl = lbl;
e.from = findNode(from);
e.to = findNode(to);
e.len = len;
edges[nedges++] = e;
}
public void run() {
while (true) {
relax();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
break;
}
}
}
synchronized void relax() {
for (int i = 0 ; i < nedges ; i++) {
Edge e = edges[i];
double vx = nodes[e.to].x() - nodes[e.from].x();
double vy = nodes[e.to].y() - nodes[e.from].y();
double len = Math.sqrt(vx * vx + vy * vy);
double f = (edges[i].len - len) / (len * 3) ;
double dx = f * vx;
double dy = f * vy;
nodes[e.to].dx += dx;
nodes[e.to].dy += dy;
nodes[e.from].dx += -dx;
nodes[e.from].dy += -dy;
}
for (int i = 0 ; i < nnodes ; i++) {
Node n1 = nodes[i];
double dx = 0;
double dy = 0;
for (int j = 0 ; j < nnodes ; j++) {
if (i == j) {
continue;
}
Node n2 = nodes[j];
double vx = n1.x() - n2.x();
double vy = n1.y() - n2.y();
double len = vx * vx + vy * vy;
if (len == 0) {
dx += Math.random();
dy += Math.random();
} else if (len < 100*100) {
dx += vx / len;
dy += vy / len;
}
}
double dlen = dx * dx + dy * dy;
if (dlen > 0) {
dlen = Math.sqrt(dlen) / 2;
n1.dx += dx / dlen;
n1.dy += dy / dlen;
}
}
Dimension d = size();
for (int i = 0 ; i < nnodes ; i++) {
Node n = nodes[i];
if (!n.fixed) {
n.x (n.x() + (int)(Math.max(-5, Math.min(5, n.dx))));
n.y (n.y() + (int)(Math.max(-5, Math.min(5, n.dy))));
if (n.x() < 0) {
n.x(0);
} else if (n.x() > d.width) {
n.x(d.width);
}
if (n.y() < 0) {
n.y(0);
} else if (n.y() > d.height) {
n.y(d.height);
}
}
n.dx /= 2;
n.dy /= 2;
}
repaint();
}
Node pick;
boolean pickfixed;
Image offscreen;
Dimension offscreensize;
Graphics offgraphics;
Font labelFont = new Font ("Helvetica", Font.PLAIN, 10);
Font nodeFont = new Font ("Helvetica", Font.PLAIN, 12);
final Color fixedColor = Color.red;
final Color selectColor = Color.pink;
final Color edgeColor = Color.black;
final Color nodeColor = new Color(250, 220, 100);
final Color arcColor1 = Color.black;
final Color arcColor2 = Color.pink;
final Color arcColor3 = Color.red;
public void paintNode(Graphics g, Node n, FontMetrics fm) {
int x = (int)n.x();
int y = (int)n.y();
if (n.name() == null)
n.name(new String ());
g.setColor(Color.green);
g.fillOval (x - 3, y - 3, 6, 6);
if (!genids && n.name().startsWith ("genid"))
return;
String sNodeName = n.name();
if (shortnames) {
int iIndex = sNodeName.indexOf ('#');
if (iIndex > 0)
sNodeName = sNodeName.substring (iIndex+1);
}
int w = fm.stringWidth(sNodeName) + 10;
int h = fm.getHeight() + 4;
g.setColor(Color.black);
g.setFont (nodeFont);
g.drawString(sNodeName,
x - (w-10)/2 + 5,
(y - (h-4)/2) + fm.getAscent() + 15);
}
public synchronized void update(Graphics g) {
Dimension d = size();
if ((offscreen == null) || (d.width != offscreensize.width) || (d.height != offscreensize.height)) {
offscreen = createImage(d.width, d.height);
offscreensize = d;
offgraphics = offscreen.getGraphics();
offgraphics.setFont(getFont());
}
offgraphics.setColor(getBackground());
offgraphics.fillRect(0, 0, d.width, d.height);
for (int i = 0 ; i < nedges ; i++) {
Edge e = edges[i];
int x1 = (int)nodes[e.from].x();
int y1 = (int)nodes[e.from].y();
int x2 = (int)nodes[e.to].x();
int y2 = (int)nodes[e.to].y();
offgraphics.setColor(arcColor1);
offgraphics.drawLine(x1, y1, x2, y2);
String sLabelName = e.lbl;
if (shortnames) {
int iIndex = sLabelName.indexOf ('#');
if (iIndex > 0)
sLabelName = sLabelName.substring (iIndex+1);
}
int w = offgraphics.getFontMetrics().stringWidth(sLabelName) + 10;
g.setFont (labelFont);
offgraphics.drawString (sLabelName,
(x1+x2)/2 - w/2 + 3,
(y1+y2)/2 + 3);
/**
* Try to make the line look like an arrow
*/
int dY = y2 - y1;
int dX = x2 - x1;
double dLength = Math.sqrt (dX*dX + dY*dY);
double dP = 10.0;
double dQ = 0.6;
int iX1 = (int)(x2 - (dX + dQ * dY) * dP/dLength);
int iY1 = (int)(y2 - (dY - dQ * dX) * dP/dLength);
int iX2 = (int)(x2 - (dX - dQ * dY) * dP/dLength);
int iY2 = (int)(y2 - (dY + dQ * dX) * dP/dLength);
offgraphics.drawLine (x2, y2, iX1, iY1);
offgraphics.drawLine (x2, y2, iX2, iY2);
}
FontMetrics fm = offgraphics.getFontMetrics();
for (int i = 0 ; i < nnodes ; i++) {
paintNode(offgraphics, nodes[i], fm);
}
g.drawImage(offscreen, 0, 0, null);
}
public synchronized boolean mouseDown(Event evt, int x, int y) {
double bestdist = Double.MAX_VALUE;
for (int i = 0 ; i < nnodes ; i++) {
Node n = nodes[i];
double dist = (n.x() - x) * (n.x() - x) + (n.y() - y) * (n.y() - y);
if (dist < bestdist) {
pick = n;
bestdist = dist;
}
}
pickfixed = pick.fixed;
pick.fixed = true;
pick.x(x);
pick.y(y);
repaint();
return true;
}
public synchronized boolean mouseDrag(Event evt, int x, int y) {
pick.x(x);
pick.y(y);
repaint();
return true;
}
public synchronized boolean mouseUp(Event evt, int x, int y) {
pick.x(x);
pick.y(y);
pick.fixed = pickfixed;
pick = null;
repaint();
return true;
}
public void start() {
relaxer = new Thread(this);
relaxer.start();
}
public void stop() {
relaxer.stop();
}
}
public class RDFGraph extends Applet {
GraphPanel panel;
private Checkbox m_genidsCB = new Checkbox ("Show generated IDs");
private Checkbox m_shortnamesCB = new Checkbox ("Element names only");
public static final String VERSION = "$Id: RDFGraph.java,v 1.1 1998/08/14 08:46:14 jsaarela Exp $";
public String getAppletInfo() {
String info = "This is RDF visualization applet version "+VERSION+
"\nby Janne Saarela <jsaarela@w3.org>. You can use it to\n" +
"interactively browse and modify RDF data models\n" +
"with some simple menu commands. "+
"This applet is based on the Graph demo applet from JavaSoft " +
"shipped with the JDK 1.0.2 distribution";
return info;
}
public void init() {
setLayout(new BorderLayout());
panel = new GraphPanel(this);
add("Center", panel);
Panel p = new Panel();
add("South", p);
p.add(new Button("Scramble"));
p.add(m_genidsCB);
m_shortnamesCB.setState (true);
p.add(m_shortnamesCB);
String edges = getParameter("triples");
Dimension dim = size();
try {
StreamTokenizer st = new StreamTokenizer (new StringBufferInputStream (edges));
st.whitespaceChars(',', ',');
int token1, token2, token3, token4, token5, token6, token7;
while ((token1 = st.nextToken()) != StreamTokenizer.TT_EOF) {
token2 = st.nextToken ();
token3 = st.nextToken ();
String sProperty = st.sval;
token4 = st.nextToken ();
String sPropertyObject = st.sval;
token5 = st.nextToken ();
String sPropertyValue = st.sval;
token6 = st.nextToken ();
token7 = st.nextToken ();
panel.addEdge(sProperty, sPropertyObject, sPropertyValue,
70);
}
} catch (Exception e) {
e.printStackTrace();
}
Dimension d = size();
String center = getParameter("center");
if (center != null){
Node n = panel.nodes[panel.findNode(center)];
n.x(d.width / 2);
n.y(d.height / 2);
n.fixed = true;
}
}
public void start() {
panel.start();
}
public void stop() {
panel.stop();
}
public boolean action(Event evt, Object arg) {
if (arg instanceof Boolean) {
if (evt.target == m_genidsCB) {
panel.genids = ((Boolean)arg).booleanValue();
} else if (evt.target == m_shortnamesCB) {
panel.shortnames = ((Boolean)arg).booleanValue();
}
return true;
}
if ("Scramble".equals(arg)) {
Dimension d = size();
for (int i = 0 ; i < panel.nnodes ; i++) {
Node n = panel.nodes[i];
if (!n.fixed) {
n.x(10 + (int)((d.width-20)*Math.random()));
n.y(10 + (int)((d.height-20)*Math.random()));
}
}
return true;
}
return false;
}
}