Mouse Events @ JavaScript xMap API

This forum deals with any kind of web based client technology, whether it is the well known java script based Ajax servlet or the upcoming approaches such as Leaflet, OpenLayers and so on.
Post Reply
tisptv
Posts: 9
Joined: Thu Sep 03, 2015 8:32 am

Mouse Events @ JavaScript xMap API

Post by tisptv »

--- EN: ------------------------------------------------------------------
For our map visualization classes we have a "Geo-Fence" editor functionality where one must be able to
(besides other things) drag a polygon rsp. a circle.

Therefore I've tried to catch mouse-events (MouseUp, MouseMove, MouseDown), but don't find any API methods which
satisfy my needs.

My tries with 'HoverArea' and 'ClickArea' did not really succeed due to these (among others) things:
- 'HoverArea' does not present any 'MouseDown' and 'MouseUp' events / callbacks,
- 'ClickArea' does provide 'MouseDown' notification, but no 'MouseUp' notification,
- Both do not fire any 'MouseMove' events while the mouse-button is down (needed for drag).

The 'VectorLayer' itself does also not seem to provide the full set.

So, any hints on the issue?

/Peter

--- DE: ------------------------------------------------------------------
für unsere Kartendarstellung haben wir eine "Geo-Fence" Editor Funktionalität, in der ein Polygon oder ein Kreis unter anderem verschoben werden muss / kann.

Daher habe ich versucht Maus-Klicks (MouseUp, MouseMove, MouseDown) abzufangen, finde aber keine Möglichkeit wie die API das ermöglichen könnte.

Meine Versuche mit 'HoverArea' und 'ClickArea' waren alle nicht 100%ig Erfolgreich, da:
- HoverArea keine MouseDown und MouseUp Benachrichtigung bietet,
- ClickArea zwar MouseDown bietet, aber keine MouseUp Benachrichtigung,
- Beide "feuern" für MouseMove keine Events sobald die Maus-taste gedrückt ist
(notwendig für "Drag").

Auch scheint der VectorLayer selbst ähnliche Unzulänglichkeiten diesbezüglich zu haben.

Irgendwelche Vorschläge diesbezüglich?
/Peter
tisptv
Posts: 9
Joined: Thu Sep 03, 2015 8:32 am

Re: Mouse Events @ JavaScript xMap API

Post by tisptv »

Nothing?
User avatar
Bernd Welter
Site Admin
Posts: 2564
Joined: Mon Apr 14, 2014 10:28 am
Contact:

Re: Mouse Events @ JavaScript xMap API

Post by Bernd Welter »

Hello Peter,

our expert provided the following example to me. It contains some approaches of selection and works fine with the tutorial (so just copy'n'paste it to your local http://127.0.0.1:50010/ajaxmaps/tutorial/tutorial.html
You can select the icons on the map via a simple click or via lasso (switch between the bodes is the right most button on the toolbar).

Code: Select all

<html>
  <head>
    <!--[if IE]>
<script type="text/javascript" src="webcomponent/script/excanvas.js"></script><![endif]-->
    <script type="text/javascript" src="webcomponent/script/qooxdoo/script/qx-transport.js"></script>
    <script type="text/javascript" src=".qxrpc"></script>
    <script type="text/javascript" src="webcomponent/script/map.js"></script>
 
    <script type="text/javascript">
 
// --> should be put into an external script
qxp.OO.defineClass("custom.VectorElement",
com.ptvag.webcomponent.map.vector.AggregateElement,
function(x, y) {
    com.ptvag.webcomponent.map.vector.AggregateElement.call(this);
    var self = this;
    var mImageMarker = null;
    var mTooltip = null;
    // --> add other elements here if needed
    var mShowingDropImage = false;
    
    if (x != null) {
        self.setX(x);
    }
    if (y != null) {
        self.setY(y);
    }
    
    var createElements = function(vectorLayer) {
        mImageMarker = new com.ptvag.webcomponent.map.vector.ImageMarker(
            self.getX(), self.getY());
        var VectorLayer = com.ptvag.webcomponent.map.layer.VectorLayer;
        mImageMarker.setAlignment(VectorLayer.ALIGN_MID_HORIZ +
                                  VectorLayer.ALIGN_MID_VERT);
        self.addElement(mImageMarker);
        mTooltip = new com.ptvag.webcomponent.map.vector.Tooltip(
            self.getX(), self.getY());
        mTooltip.setText("Tooltip-Test");
        mTooltip.setDependsOn(mImageMarker.getId());
        self.addElement(mTooltip);
        // --> create other elements here if needed
        setUrl();
    };

    self.dragOver = function(element) {
        // return false if element can't be dropped here
        mShowingDropImage = true;
        setUrl();
        return true;
    };
    
    self.dragOut = function(element) {
        mShowingDropImage = false;
        setUrl();
    };
    
    self.drop = function(element) {
        mShowingDropImage = false;
        setUrl();
        alert("Dropped");
    };
    
    self.setOpacity = function(opacity) {
        if (mImageMarker != null) {
            mImageMarker.setOpacity(opacity);
        }
    };
    
    self._modifyX = function(propValue) {
        if (mImageMarker != null) {
            mImageMarker.setX(propValue);
        }
        if (mTooltip != null) {
            mTooltip.setX(propValue);
        }
        // --> modify other elements here if needed
    };
    
    self._modifyY = function(propValue) {
        if (mImageMarker != null) {
            mImageMarker.setY(propValue);
        }
        if (mTooltip != null) {
            mTooltip.setY(propValue);
        }
        // --> modify other elements here if needed
    };
    
    var setUrl = function() {
        if (mImageMarker != null) {
            if (mShowingDropImage) {
                mImageMarker.setUrl(
                    "webcomponent/img/com/ptvag/webcomponent/map/button_reset.gif");
            } else if (self.getSelected()) {
                mImageMarker.setUrl(
                    "webcomponent/img/com/ptvag/webcomponent/map/button_zoom_in.gif");
            } else {
                mImageMarker.setUrl(
                    "webcomponent/img/com/ptvag/webcomponent/map/button_zoom_out.gif");
            }
        }
    };
    
    self._modifySelected = function(propValue) {
        setUrl();
    };
    
    // overridden
    var superModifyVectorLayer = self._modifyVectorLayer;
    self._modifyVectorLayer = function(propValue) {
        superModifyVectorLayer.apply(self, arguments);
        if (propValue != null) {
            createElements(propValue);
        }
    };
});

qxp.OO.addProperty({ name:"x", type:qxp.constant.Type.NUMBER, allowNull:false });
qxp.OO.addProperty({ name:"y", type:qxp.constant.Type.NUMBER, allowNull:false });
qxp.OO.addProperty({ name:"selectable", type:qxp.constant.Type.BOOLEAN,
                     allowNull:false, defaultValue:false });
qxp.OO.addProperty({ name:"selected", type:qxp.constant.Type.BOOLEAN,
                     allowNull:false, defaultValue:false });
qxp.OO.addProperty({ name:"draggable", type:qxp.constant.Type.BOOLEAN,
                     allowNull:false, defaultValue:false });
// <--


// --> should be put into an external script
qxp.OO.defineClass("custom.VectorLayer",
com.ptvag.webcomponent.map.layer.VectorLayer,
function(floaterLayer, isSecondary) {
    com.ptvag.webcomponent.map.layer.VectorLayer.call(this, floaterLayer,
        (isSecondary == null ? true : isSecondary));
 
    var self = this;
    var mapPackage = com.ptvag.webcomponent.map;
    var vectorPackage = mapPackage.vector;
    var CoordUtil = mapPackage.CoordUtil;
    var EventUtils = com.ptvag.webcomponent.util.EventUtils;
 
    var significantMovementDist = 9;
    var significantMovementSquareDist =
        significantMovementDist*significantMovementDist;
 
    var mLassoLine = null;
    var mCurrentElement = null;
    var mSelectableElements = {};
    var mDropTargets = {};
    var mDragElementStartPoint;
    var mMouseStartPoint;
    var mSignificantMovement;
    var mDropTarget = null;
 
    var resetSelection = function() {
        for (var id in mSelectableElements) {
            var element = mSelectableElements[id];
            element.setSelected(false);
        }
    }
 
    self.getSelection = function() {
        var selectedElements = [];
        for (var id in mSelectableElements) {
            var element = mSelectableElements[id];
            if (element.getSelected()) {
                selectedElements.push(element);
            }
        }
        return selectedElements;
    };
 
    var superAddElement = self.addElement;
    self.addElement = function(element) {
        var id = superAddElement.apply(self, arguments);
        if (element.getSelectable && element.getSelectable()) {
            mSelectableElements[id] = element;
        }
        if (element.dragOver && element.dragOut && element.drop) {
            mDropTargets[id] = element;
        }
        return id;
    };
 
    var superRemoveElement = self.removeElement;
    self.removeElement = function(id) {
        delete mSelectableElements[id];
        delete mDropTargets[id];
        superRemoveElement.apply(self, arguments);
    };

    var positionElement = function(element, position) {
        var alreadyInBulkMode = self.inBulkMode();
        if (!alreadyInBulkMode) {
            self.startBulkMode();
        }
        element.setX(position.x);
        element.setY(position.y);
        element.setOpacity(mSignificantMovement ? 0.3 : 1);
        if (!alreadyInBulkMode) {
            self.endBulkMode();
        }
    };
    
    var superOnMouseDown = self.onMouseDown;
    self.onMouseDown = function(evt) {
        if (mLassoLine != null) {
            // safeguard
            var lassoLayer = mLassoLine.getVectorLayer();
            if (lassoLayer != null) {
                // safeguard
                lassoLayer.removeElement(mLassoLine.getId());
            }
            mLassoLine = null;
        }
        if (mCurrentElement != null) {
            // safeguard
            if (mSignificantMovement) {
            	mSignificantMovement = false;
                positionElement(mCurrentElement, mDragElementStartPoint);
                if (mDropTarget != null) {
                    mDropTarget.dragOut(mCurrentElement);
                    mDropTarget = null;
                }
            }
            mCurrentElement = null;
            mDropTarget = null;
        }
        if (!com.ptvag.webcomponent.util.EventUtils.isLeftMouseButton(evt)) {
            return superOnMouseDown.apply(self, arguments);
        }
        mMouseStartPoint = {relMouseX:evt.relMouseX, relMouseY:evt.relMouseY};
        var startPoint = self.getMap().translateMouseCoords(mMouseStartPoint);
        var modifiers = EventUtils.getModifiers(evt);
 
        var bounds = self.getMap().getRect();
        var left = bounds.left;
        var right = bounds.right;
        var top = bounds.top;
        var bottom = bounds.bottom;
        var minDist = -1;
        var visibleZoom = self.getMap().getVisibleZoom();
        startPointPix = CoordUtil.smartUnit2Pixel(startPoint, visibleZoom);
        for (var id in mSelectableElements) {
            var element = mSelectableElements[id];
            var x = element.getX();
            var y = element.getY();
            if (x < left || x > right || y < bottom || y > top) {
                continue;
            }
            var pixPoint = CoordUtil.smartUnit2Pixel(
                {x:x, y:y}, visibleZoom);
            var distX = pixPoint.x - startPointPix.x;
            var distY = pixPoint.y - startPointPix.y;
            var squareDist = distX*distX + distY*distY;
            if (squareDist <= significantMovementSquareDist) {
                if (minDist < 0 || squareDist < minDist) {
                    minDist = squareDist;
                    mCurrentElement = element;
                }
            }
        }
        if (mCurrentElement != null) {
            self.setLassoMode(false);
            if (modifiers & EventUtils.SHIFT_MASK) {
                if (mCurrentElement.getSelected()) {
                    mCurrentElement.setSelected(false);
                } else {
                    mCurrentElement.setSelected(true);
                }
            } else {
                resetSelection();
                mCurrentElement.setSelected(true);
            }
            if (self.hasEventListeners("selectionChanged")) {
                self.createDispatchEvent("selectionChanged");
            }
            if (mCurrentElement.getDraggable && mCurrentElement.getDraggable()) {
                mSignificantMovement = false;
                mDragElementStartPoint = {x:mCurrentElement.getX(),
                                          y:mCurrentElement.getY()};
            }
            self.getMap().getController().setActiveLayer(self);
            return true;
        }

        if (!self.getLassoMode()) {
            return superOnMouseDown.apply(self, arguments);
        }
        var lassoCoords = [startPoint.x, startPoint.y];
        mLassoLine = new vectorPackage.Line("rgba(0,0,0,0.7)", 4,
            lassoCoords, 1000);
        self.addElement(mLassoLine);
        self.getMap().getController().setActiveLayer(self);
        return true;
    };
 
    var superOnMouseMove = self.onMouseMove;
    self.onMouseMove = function(evt) {
        if (mCurrentElement == null && mLassoLine == null) {
            return superOnMouseMove.apply(self, arguments);
        }
        var newPoint = self.getMap().translateMouseCoords(evt);
        if (mLassoLine != null) {
            var lassoCoords = mLassoLine.getCoordinates();
            lassoCoords.push(newPoint.x);
            lassoCoords.push(newPoint.y);
            mLassoLine._modifyCoordinates(lassoCoords);
        }
        if (mCurrentElement != null &&
            mCurrentElement.getDraggable && mCurrentElement.getDraggable()) {
            if (!mSignificantMovement) {
                var distX = evt.relMouseX - mMouseStartPoint.relMouseX;
                var distY = evt.relMouseY - mMouseStartPoint.relMouseY;
                var squareDist = distX*distX + distY*distY;
                if (squareDist > significantMovementSquareDist) {
                    mSignificantMovement = true;
                }
            }
            if (mSignificantMovement) {
                positionElement(mCurrentElement, newPoint);
                var bounds = self.getMap().getRect();
                var left = bounds.left;
                var right = bounds.right;
                var top = bounds.top;
                var bottom = bounds.bottom;
                var minDist = -1;
                var visibleZoom = self.getMap().getVisibleZoom();
                var newPointPix = CoordUtil.smartUnit2Pixel(newPoint, visibleZoom);
                var newDropTarget = null;
                for (var id in mDropTargets) {
                    var element = mDropTargets[id];
                    if (element == mCurrentElement) {
                        continue;
                    }
                    var x = element.getX();
                    var y = element.getY();
                    if (x < left || x > right || y < bottom || y > top) {
                        continue;
                    }
                    var pixPoint = CoordUtil.smartUnit2Pixel(
                        {x:x, y:y}, visibleZoom);
                    var distX = pixPoint.x - newPointPix.x;
                    var distY = pixPoint.y - newPointPix.y;
                    var squareDist = distX*distX + distY*distY;
                    if (squareDist <= significantMovementSquareDist) {
                        if (minDist < 0 || squareDist < minDist) {
                            minDist = squareDist;
                            newDropTarget = element;
                        }
                    }
                }
                if (newDropTarget != mDropTarget) {
                    if (mDropTarget != null) {
                        mDropTarget.dragOut(mCurrentElement);
                        mDropTarget = null;
                    }
                    if (newDropTarget != null) {
                        if (newDropTarget.dragOver(mCurrentElement)) {
                            mDropTarget = newDropTarget;
                        }
                    }
                }
            }
        }
        return false;
    };
 
    var superOnMouseUp = self.onMouseUp;
    self.onMouseUp = function(evt) {
        if (mCurrentElement == null && mLassoLine == null) {
            return superOnMouseUp.apply(self, arguments);
        }
        if (mLassoLine != null) {
            var lassoCoords = mLassoLine.getCoordinates();
            var lassoLayer = mLassoLine.getVectorLayer();
            if (lassoLayer != null) {
                // safeguard
                lassoLayer.removeElement(mLassoLine.getId());
            }
            mLassoLine = null;
            self.setLassoMode(false);
            var bounds = self.getMap().getRect();
            var left = bounds.left;
            var right = bounds.right;
            var top = bounds.top;
            var bottom = bounds.bottom;
            var modifiers = EventUtils.getModifiers(evt);
            var shiftPressed = (modifiers & EventUtils.SHIFT_MASK);
            if (!shiftPressed) {
                resetSelection();
            }
            for (var id in mSelectableElements) {
                var element = mSelectableElements[id];
                var x = element.getX();
                var y = element.getY();
                if (x < left || x > right || y < bottom || y > top) {
                    continue;
                }
                if (CoordUtil.isPointInPoly(x, y, lassoCoords)) {
                    if (shiftPressed) {
                        element.setSelected(
                            !element.getSelected());
                    } else {
                        element.setSelected(true);
                    }
                }
            }
            if (self.hasEventListeners("selectionChanged")) {
                self.createDispatchEvent("selectionChanged");
            }
        }
        if (mCurrentElement != null) {
            if (mSignificantMovement) {
            	mSignificantMovement = false;
                positionElement(mCurrentElement, mDragElementStartPoint);
                if (mDropTarget != null) {
                    mDropTarget.drop(mCurrentElement);
                    mDropTarget = null;
                }
            }
            mCurrentElement = null;
        }
        self.getMap().getController().setActiveLayer(null);
        return true;
    };
 
    var superOnMouseClick = self.onMouseClick;
    self.onMouseClick = function(evt) {
        resetSelection();
        if (self.hasEventListeners("selectionChanged")) {
            self.createDispatchEvent("selectionChanged");
        }
        return superOnMouseClick.apply(self, arguments);
    };
 
    var superOnMouseOut = self.onMouseOut;
    self.onMouseOut = function(evt) {
        if (mCurrentElement == null && mLassoLine == null) {
            return superOnMouseOut.apply(self, arguments);
        }
        if (mLassoLine != null) {
            var lassoLayer = mLassoLine.getVectorLayer();
            if (lassoLayer != null) {
                // safeguard
                lassoLayer.removeElement(mLassoLine.getId());
            }
            mLassoLine = null;
            self.setLassoMode(false);
        }
        if (mCurrentElement != null) {
            if (mSignificantMovement) {
            	mSignificantMovement = false;
                positionElement(mCurrentElement, mDragElementStartPoint);
                if (mDropTarget != null) {
                    mDropTarget.dragOut(mCurrentElement);
                    mDropTarget = null;
                }
            }
            mCurrentElement = null;
        }
        self.getMap().getController().setActiveLayer(null);
        return false;
    };
 
    var superOnKeyDown = self.onKeyDown;
    self.onKeyDown = function(evt) {
        if (evt.keyCode != EventUtils.KEY_CODE_ESC ||
            mCurrentElement == null && mLassoLine == null) {
            return superOnKeyDown.apply(self, arguments);
        }
        self.onMouseOut();
        self.getMap().getController().ignoreNextClick();
            // otherwise, a click event would be generated by the following
            // mouse up
        return true;
    };
});
 
qxp.OO.addProperty({ name:"lassoMode", type:qxp.constant.Type.BOOLEAN,
    allowNull:false, defaultValue:false });
// <--
 
 
      function init() {
        var container =
          document.getElementById("mapContainer");
        var map =
          new com.ptvag.webcomponent.map.Map(container);
 
        map.setCenter({x:4303250, y:5486500});
        map.setZoom(10);
 
        var floaterLayer = map.getLayer("floater");
        var vectorLayer = new custom.VectorLayer(
          floaterLayer);
        vectorLayer.setIsRelative(true);
        map.addLayer(vectorLayer, "customVectorLayer", null, floaterLayer);
 
        var element1 = new custom.VectorElement();
        element1.setX(4303326);
        element1.setY(5487054);
        element1.setSelectable(true);
        element1.setDraggable(true);
        vectorLayer.addElement(element1);
        var element2 = new custom.VectorElement();
        element2.setX(4303250);
        element2.setY(5486500);
        element2.setSelectable(true);
        element2.setDraggable(true);
        vectorLayer.addElement(element2);
        
        var infoLayerWidth = 80;
        var infoLayerHeight = 25;
        var additionalSpace = infoLayerHeight + 10;
        var zoomSliderLayer = map.getLayer("zoomslider");
        var zoomSliderTop = zoomSliderLayer.getAreaTop();
        zoomSliderLayer.setAreaTop(
          zoomSliderTop + additionalSpace);
        var compassLayer = map.getLayer("compass");
        var compassTop = compassLayer.getAreaTop();
        var compassRight = compassLayer.getAreaRight();
        compassLayer.setAreaTop(
          compassTop + additionalSpace);
 
        var infoLayer =
          new com.ptvag.webcomponent.map.layer.AbstractStaticAreaLayer();
        infoLayer.set({areaRight:compassRight,
                       areaTop:compassTop,
                       areaWidth:infoLayerWidth,
                       areaHeight:infoLayerHeight});
        map.addLayer(infoLayer, "customInfoLayer", 1, null, false);
 
        var areaElement = document.createElement("div");
        areaElement.style.position = "absolute";
        areaElement.style.left = "0px";
        areaElement.style.top = "0px";
        areaElement.style.backgroundColor = "white";
        areaElement.style.border = "1px solid black";
        var infoElement = document.createElement("div");
        infoElement.style.height = "100%";
        infoElement.style.fontFamily = "Arial";
        infoElement.style.fontSize = "12px";
        infoElement.style.color = "black";
        infoElement.style.padding = "5px";
        infoElement.style.textAlign = "center";
        areaElement.appendChild(infoElement);
        infoLayer.setAreaBorderWidth(1);
        infoLayer.onMouseDown = infoLayer.onMouseUp = function(evt) {
          if (infoLayer.isPositionInArea(evt.relMouseX, evt.relMouseY)) {
            return true;
          }
          return false;
        };
        infoLayer.getParentElement().appendChild(areaElement);
        infoLayer.setAreaElement(areaElement);
        infoLayer.setAreaOpacity(infoLayer.getBlendingOpacityOver());
 
        var updateInfo = function(selection) {
          var count = selection.length;
          infoElement.innerHTML = "Selected: " + count;
        };
        updateInfo([]);
 
        vectorLayer.addEventListener("selectionChanged", function(evt) {
          updateInfo(vectorLayer.getSelection());
        });
 
        var toolbarLayer = map.getLayer("toolbar");
        toolbarLayer.addElement({width:7, id:"spacer"});
        var lassoDefaultURL =
          "webcomponent/img/com/ptvag/webcomponent/map/button_overview.gif";
        var lassoSelectedURL =
          "webcomponent/img/com/ptvag/webcomponent/map/button_overview_highlight.gif";
        var lassoMode = vectorLayer.getLassoMode();
        toolbarLayer.addElement({
          id:"lassoButton",
          imgUrl:(lassoMode ? lassoSelectedURL : lassoDefaultURL),
          width:17, height:17, tooltip:"Toggle lasso mode",
          enabled:true, clickHandler: function() {
            var lassoMode = !vectorLayer.getLassoMode();
            vectorLayer.setLassoMode(lassoMode);
          }
        });
 
        vectorLayer.addEventListener("changeLassoMode", function(evt) {
          var lassoMode = vectorLayer.getLassoMode();
          toolbarLayer.setButtonImage("lassoButton",
            (lassoMode ? lassoSelectedURL : lassoDefaultURL));
        });
      }
 
      qxp.dev.log.Logger.ROOT_LOGGER.setMinLevel(qxp.dev.log.Logger.LEVEL_INFO);
      qxp.dev.log.Logger.getClassLogger(qxp.core.Init).setMinLevel(qxp.dev.log.Logger.LEVEL_ERROR);
    </script>
  </head>
 
  <body onload="init()">
    <div id="mapContainer"
      style="width:100%;height:100%">
    </div>
  </body>
</html>
Sorry for the late response,
we work on our speed ;-)

Best regards Bernd
tisptv
Posts: 9
Joined: Thu Sep 03, 2015 8:32 am

Re: Mouse Events @ JavaScript xMap API

Post by tisptv »

Bernd Welter wrote: Sorry for the late response,
we work on our speed ;-)
Same here: Sorry for the late response ;) ...other probelms always seem to intermitt...

The provided code helped a lot! thank you.

Best regards
Peter
Post Reply