Page 1 of 1

Mouse Events @ JavaScript xMap API

Posted: Thu Sep 10, 2015 5:03 pm
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

Re: Mouse Events @ JavaScript xMap API

Posted: Tue Nov 24, 2015 10:17 am
by tisptv
Nothing?

Re: Mouse Events @ JavaScript xMap API

Posted: Wed Nov 25, 2015 12:18 pm
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

Re: Mouse Events @ JavaScript xMap API

Posted: Fri Feb 19, 2016 11:03 am
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