At 08:46 AM 11/24/99 -0600, Adam Hill wrote:
>Could you run it in IE5 and let us know if it works? (or send a sample
>file we can test?)

Yeah, and if I don't write it up now I won't get around to it, so here goes.

Problem: based on some event in your J3D environment, which is running
in an applet, you want to achieve a visible effect in the browser but
outside the applet.

Let us suppose that we have some objects in the scene which have some
associated descriptive information, and you want, when the mouse goes
over them, to display that descriptive text, say below the applet.  You
could try tooltips or Text2D or so on, but then you'd have to do line
breaks, which is silly because the browser has a nice built-in
text-renderer.

First, the key points to watch for, then a bunch of real code.

All this has only been tested in IE5.  In fact, it near certainly won't
work in NS because of the docment.all/document.layers collection breakage;
if you wanted both, the smart thing would be to write a little function that
works around the breakage, and call that function via JSObject.eval().  I
learned how to write such functions by reading the DHTML tutorial at
Webmonkey under hotwired.com.

1. The HTML page

Key points:
- the <OBJECT > tag has to have the MAYSCRIPT param with value "true".
- if you want to meddle with the HTML page, you'd better put something in
  with an ID attribute so you can get at it

2. The ShapePlus Class

When you pick or mouse-over something, you're going to want to
retrieve the descriptive information, which is easy, just extend
Shape3D and provide a member variable for that.

3. MouseOver

I recommend throwing out the utils.behaviors.picking.PickMouseBehavior,
stealing a couple of things from it, and replacing it.  First, it's
badly written and hardly documented at all; e.g., it doesn't tell you
that the constructor doesn't set the bounds and so won't work unless
extended.  Second, it doesn't do mouse motion at all.  So I've attached
"Picker.java" below, which is what I use.  It could still be improved
(e.g. by someone unlike me who understands AWT stuff) but it runs OK.

4. Dealing with Javascript

You have have to use a netscape.javascript.JSObject, which is essentially
a java handle to the Javascript view of the page you're in.  The class has
a static method, you pass in the Applet object & it gives you back a
JSObject, so that's easy.

The docs (and here was the single hardest part of doing this) may be
found at

  http://home.netscape.com/eng/mozilla/3.0/handbook/plugins/doc/packages.html

Apparently, JSObject allows you to walk through the document tree,
but that wasn't well documented; on the other hand it has an eval(String)
method that you just past a string of J. Random Javascript to, and the
first time I tried this, it did exactly what I meant.

So, you want to compile this, do you?  The class files may be found
(on WinNT) in
C:\program files\netscape\communicator\program\java\classes\java40.jar

I found the easiest thing to do was just

        jar xf <that file above> netscape

right in my dev directory, then I could compile.

Note that I used the "innerHTML" property in the javascript.  This means
you can have HTML tags in your description and the browser will render
them.  I learned about this by looking it up in Scott Isaac's book "Inside
Dynamic HTML", not that it might not be well-documented elsewhere, but it's
there for sure.

Good luck; you'll need it. -Tim

=======The HTML===============
<html><head><title>whatever</title></head>
<body>
<!--omitted stuff -->
<!-- note in particular the "mayscript" parameter - you need this! -->
<OBJECT classid='clsid:8AD9C840-044E-11D1-B3E9-00805F499D93'
        width='547' height='453'
       
java_codebase='http://java.sun.com/products/plugin/1.2/jinstall-12-win32.cab#Version=1,2,0,0'
       style='position:absolute;top:50;left:91; height:453;width:547;'>
 <PARAM NAME='java_code' VALUE=whatever.class'>
 <PARAM NAME='archive' VALUE='whatever.jar'>
 <PARAM NAME='mayscript' VALUE='true'>
 <PARAM NAME='codebase' VALUE='/whatever/'>
 <PARAM NAME='java_type' VALUE='application/x-java-applet;version=1.2'>
 <PARAM NAME='ash_path' VALUE='1.7.6.9.4.7.2.2.1.9'>
</OBJECT>
<!-- NOTE empty para here with ID attribute -->
<p id='descr' style='width:547;position:absolute;top:503;left:91'> </p>
</body>
</html>

====ShapePlus.class===============================
import javax.media.j3d.*;
/* a Shape3D with some ancillary info, for picking */
public class ShapePlus extends Shape3D
{
  String mDescription;
  public ShapePlus(String desc)  {
    super();
    mDescription = desc;
  }
  public String desc() { return mDescription; }
}

=======Picker.java=====================
import javax.swing.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.picking.*;
import java.net.URL;
import netscape.javascript.*;
import java.util.Enumeration;

//quite a bit of this stolen from the j3d.util.PickMouseBehavior
public class Picker extends Behavior
{
  JSObject mJSDoc;
  PickObject mPickScene;
  WakeupCriterion[] mConditions;
  WakeupOr mWakeupCondition;
  boolean mPressed = false;
  MouseEvent mEvent;
  Shape3D mLastShape = null;

  public Picker(BranchGroup root, Canvas3D canvas, Bounds bounds,
                Applet applet)
  {
    super();
    mPickScene = new PickObject(canvas, root);
    mJSDoc = JSObject.getWindow(applet);
    mJSDoc = (JSObject) mJSDoc.getMember("document"); // not sure I need this
    this.setSchedulingBounds(bounds);
  }

  public void initialize()
  {
    mConditions = new WakeupCriterion[2];
    mConditions[0] = new WakeupOnAWTEvent(Event.MOUSE_MOVE);
    mConditions[1] = new WakeupOnAWTEvent(Event.MOUSE_DOWN);
    mWakeupCondition = new WakeupOr(mConditions);
    wakeupOn(mWakeupCondition);
  }

  // routine should be inlined.
  private void processMouseEvent(MouseEvent evt)
  {
    mPressed = (evt.getID() == MouseEvent.MOUSE_PRESSED ||
                evt.getID() == MouseEvent.MOUSE_CLICKED);
  }

  public void processStimulus (Enumeration criteria)
  {
    WakeupCriterion wakeup;
    AWTEvent[] evt = null;

    while(criteria.hasMoreElements())
    {
      wakeup = (WakeupCriterion) criteria.nextElement();
      if (wakeup instanceof WakeupOnAWTEvent)
        evt = ((WakeupOnAWTEvent) wakeup).getAWTEvent();
    }

    if (evt[0] instanceof MouseEvent)
    {
      mEvent = (MouseEvent) evt[0];
      processMouseEvent((MouseEvent)evt[0]);
      dealWith(mEvent.getPoint().x, mEvent.getPoint().y);
    }
    wakeupOn (mWakeupCondition);
  }

  private void dealWith(int xPos, int yPos)
  {
    SceneGraphPath sgPath = null;
    Shape3D shape = null;

    // is there anything pickable there?
    sgPath = mPickScene.pickClosest(xPos, yPos, PickObject.USE_BOUNDS);
    if (sgPath != null)
      shape = (Shape3D) mPickScene.pickNode(sgPath, PickObject.SHAPE3D);

    if ((sgPath == null) || (shape == null) || !(shape instanceof ShapePlus))
    {
      if (mLastShape != null)
      {
        mLastShape = null;
        mJSDoc.eval("document.all.descr.innerHTML=\" \"");
      }
      return;
    }

    // if they clicked, do that stuff
    if (mPressed)
    {
       // omitted
       return;
    }

    // just a motion;
    if (shape == mLastShape)
      return;

    mLastShape = shape;
    String desc = ((ShapePlus) shape).desc();
    mJSDoc.eval("document.all.descr.innerHTML=\"" + desc + "\";");
  }
}

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA3D-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to