1

I have tried various methods of getting the mouse coordinates into the backing bean when a user clicks on an image. I can get the coordinates in the javascript, it then calls the ajax listener, but the parameters are not in the request.

my js:

if (!cis) var cis = {}
if (!cis.sarwinds) {
  var focusLostTimeout
  cis.sarwinds = {   
    errorHandler: function(data) { 
      alert("Error occurred during Ajax call: " + data.description) 

    },

    updateZoomValues: function(input, event) { 



       jsf.ajax.addOnError(cis.sarwinds.errorHandler)
          var offset = jQuery(input).offset();       

          jsf.ajax.request(input, event, { 
             render: "imagePan2 message",
             x: event.pageX - offset.left,
             y: event.pageY - offset.top
          })
    },

    getGraphicImageId: function(input) {
      var clientId = new String(input.name)
      var lastIndex = clientId.lastIndexOf(":")
      return clientId.substring(0, lastIndex) + ":imagePan2"
    }
  } 
}

My jsf page element:

    <h:graphicImage id="imagePan2" library="images" styleClass="wind_map" name="testImage.jpg" style="#{SarWindsImagesBean.imageStyle('testImage.jpg')}">
           <f:ajax event="click" onevent="cis.sarwinds.updateZoomValues(this, event)" listener="#{SarWindsImagesBean.zoomInClick}" render="imagePan2 message"/>
    </h:graphicImage>

My Backing bean:

    public void zoomInClick(AjaxBehaviorEvent event) {
    double width;
    double height;
    double top;
    double left;
    double mouseX;
    double mouseY;
    String fileName = "testImage";


    Map<String, String> reqParams = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
    mouseX = Double.parseDouble(reqParams.get("x"));
    mouseY = Double.parseDouble(reqParams.get("y"));


    width = imageItems.get(fileName).getImageWidth() * 1.1;
    height = imageItems.get(fileName).getImageHeight() * 1.1;

    // We need the mouse position on the image here, and we need to calculate
    top = mouseY - ((mouseY - imageItems.get(fileName).getImageTop()) * 1.1);
    left = mouseX - ((mouseX - imageItems.get(fileName).getImageLeft()) * 1.1);

    if (this.imageLock == false){

        imageItems.put(fileName, new SarWindImageItem(width, height, top, left));
    } else {
        Iterator<String> it = imageItems.keySet().iterator();
        while (it.hasNext()) {

                String key = (String)it.next();

                imageItems.put(key, new SarWindImageItem(width, height, top, left));
            }
    }
}

The reqParams are empty.

Dan

Danpoleary
  • 49
  • 2
  • 8

2 Answers2

0

<input type="image"> can be typically used in this type of case. It has passed the coordinates along with the form submission since the 90s. No need for JS trickery.

If you do find to need to grab this values via JS, here's a solution:

get click coordinates from <input type='image'> via javascript

Community
  • 1
  • 1
Diodeus - James MacFarlane
  • 112,730
  • 33
  • 157
  • 176
  • You forgot to answer how to integrate it seamlessly in JSF. You seem to never have developed in JSF. – BalusC Oct 31 '12 at 15:17
0

The way how you used jsf.ajax.request() isn't entirely right. The <f:ajax> already creates one, but then you're nesting another one in its onevent (note that the onevent is called thrice; before the request is been sent, after the response is arrived and after the HTML DOM is updated). This isn't right.

Technically, you should be calling jsf.ajax.request() in the onclick attribute instead and remove the <f:ajax> altogether. However, this basically requires replacing the <h:graphicImage> by a homebrewed UIComponent which does the request parameter collecting job in decode() method so that the appropriate model values can properly be updated.

Forget using the jsf.ajax.request() standalone. It should only be used when you're really developing a custom UIComponent wherein you perform the desired postprocessing in decode().

Plain vanilla HTML offers an <input type="image" name="foo"> for this on which the coordinates would be sent as foo.x and foo.y parameters. This works in JSF with <h:commandButton image="some.png">, however, those special parameters aren't been sent when you're using <f:ajax>. So forget this.

Your best bet would be setting hidden input values with the desired coordinates and in turn bind those hidden inputs to managed bean properties the usual way.

E.g.

<h:form>
    <h:graphicImage id="image" name="image1.png">
        <f:ajax event="click" execute="x y" listener="#{bean.listener}" />
    </h:graphicImage>
    <h:inputHidden id="x" value="#{bean.x}" />
    <h:inputHidden id="y" value="#{bean.y}" />
</h:form>

<h:outputScript>
    jQuery("img[id$=':image']").on("mousedown", function(event) {
        var $form = jQuery(this).closest("form");
        $form.find("input[id$=':x']").val(event.pageX);
        $form.find("input[id$=':y']").val(event.pageY);
    });
</h:outputScript>

(note: jQuery.on() is only available since 1.7, if you're using an older version, use jQuery.bind() instead)

with

@ManagedBean
@RequestScoped
public class Bean {

    private Integer x;
    private Integer y;

    public void listener() {
        System.out.println(x + ", " + y);
    }

    // ...
}

Note that I also fixed your incorrect way of getting the mouse position. You just returned the position of the image element itself, not the position of the mouse pointer on it.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I tried this just now, but keep getting "serverError: org.apache.myfaces.view.facelets.el.ContextAwareELException javax.el.ELException: java.lang.NullPointerException Note, this message is only sent, because project stage is development and no other error listeners are registered." – Danpoleary Oct 31 '12 at 16:44
  • Ah, MyFaces ... Replace `int` by `Integer`. I updated the answer. This by the way suggests that the hidden inputs are not been set at all. Have you copypasted the exact code or modified it a bit too much? – BalusC Oct 31 '12 at 16:47
  • I think I found my issue. I modified it to fit the session backing bean logic I have for binding image layers to the same coordinate click. I am trying it out now and will post my results. Thank you for the feedback. – Danpoleary Oct 31 '12 at 16:58
  • It partially works. It appears, that when the image re-renders on return, and I do a subsequent click, it is not updating the coordinates. It only takes the values from the first time I clicked. – Danpoleary Oct 31 '12 at 19:02
  • The example in my answer doesn't update the image at all. If you're updating the image on ajax response for some reason (is that really mandatory? shouldn't you rather be updating other parts?), then you'd need to update the outputscript as well in order to re-execute it (so that the lost event handler get rebinded). Alternatively, you could move the job to `onclick` attribute, but then you'd need to take browser specific issues of `event.pageX` and `event.pageY` into account yourself (when binding by jQuery, jQuery has already done it transparently for you by replacing the `event` argument). – BalusC Oct 31 '12 at 19:03
  • Thank you, with what you provided, and a little work on the back end, and I was able to get everything working great. I am not updating the image itself, but the issue I had, was that I had four satellite shots, using different wavelengths, and I need all to be perfectly overlapping. So when A user zoomed or panned one, then switched wavelengths, the other images will be zoomed and panned to the same level. I could do it all in javascript, and maintain the layers, but I had to provide another method that does not require scripting at all. Now both versions work well. – Danpoleary Nov 01 '12 at 11:29