Клуб API Карт

Не получается передать мышиные события карте

skier2006
20 ноября 2014, 12:30

есть вот такая страничка:

 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40">

<html>

<head>

<style type="text/css"> html {overflow:hidden}</style>

<style type="text/css">

 

html, body

{

  width : 100%;

  height : 100%;

}

 

#map

{

  width : 100%;

  height : 100%;

  position: absolute;  

  z-index: 0;

}

 

#mapcanvas

{

  left: 0;

  top: 0;

  margin: 0px 0px 0px 0px;

  padding : 0px;

  position: absolute;   

  z-index: 1;

  <!--pointer-events:none;-->

}

 

body 

{

  margin: 0;

  padding: 0;

}

 

</style>

<title>Yandex 2.0</title>

<script src="http://api-maps.yandex.ru/2.0.35/?load=package.full&mode=debug&lang=ru-RU&coordorder=longlat" type="text/javascript"></script>

<script type="text/javascript">

ymaps.ready(init);

var lon=37.61770

var lat=55.75582

var zoom=11

var map;

function init() {

map = new ymaps.Map("map", {

     center: [lon,lat]

 }

);

map.behaviors.enable("scrollZoom");

map.setCenter([lon,lat], zoom, {checkZoomRange: false});

}

function YaUnload() {

map.destroy();

}

 

function getRandomArbitary(min, max)

{

  return Math.floor(Math.random() * (max - min + 1)) + min;

}

 

function drawRects() {

  var c = document.getElementById("mapcanvas");

  var ctx = c.getContext("2d");

   c.width = document.getElementById("map").clientWidth;

   c.height = document.getElementById("map").clientHeight;

   ctx.clearRect(0, 0, c.width, c.height);

   var min = 1;

   var max = 1000;

   for (var i = min; i < max; i++){

ctx.fillStyle="#" + getRandomArbitary(1, c.width);

ctx.fillRect(getRandomArbitary(1, c.width), getRandomArbitary(1, c.height), 8, 8);

   }

}

 

</script>

</head>

<body onunload=YaUnload()>

<div style="width:100%; height:100%" id="base">

<!--<input type="button" value="Draw images" onclick="drawImages();"/>--> 

<canvas id="mapcanvas">

</canvas>

<div id="map">

</div>

</div>

<script>

 

var mapcanvas = document.getElementById("mapcanvas");

var mapdiv = document.getElementById("map");

var basediv = document.getElementById("base");

 

mapcanvas.onclick = function(e){

e.preventDefault();

 

var evt = document.createEvent("MouseEvents");

  evt.initMouseEvent("click",

           true, //canBubble

           false, //cancelable

           window, //event's AbstractView : should be window 

           1, // detail : Event's mouse click count 

           e.screenX, // screenX

           e.screenY, // screenY

           e.clientX, // clientX

           e.clientY, // clientY

           e.ctrlKey, // ctrlKey

           e.altKey, // altKey

           e.shiftKey, // shiftKey

           e.metaKey, // metaKey 

           0, // button : 0 = click, 1 = middle button, 2 = right button  

           null // relatedTarget

 

);

mapdiv.dispatchEvent(evt);

 

 

}

 

mapcanvas.onmousedown = function(e){

e.preventDefault();

 

var evt = document.createEvent("MouseEvents");

  evt.initMouseEvent("mousedown",

           true, //canBubble

           false, //cancelable

           window, //event's AbstractView : should be window 

           1, // detail : Event's mouse click count 

           e.screenX, // screenX

           e.screenY, // screenY

           e.clientX, // clientX

           e.clientY, // clientY

           e.ctrlKey, // ctrlKey

           e.altKey, // altKey

           e.shiftKey, // shiftKey

           e.metaKey, // metaKey 

           0, // button : 0 = click, 1 = middle button, 2 = right button  

           null // relatedTarget

);

mapdiv.dispatchEvent(evt);

 

}

 

mapcanvas.onmousemove = function(e){

e.preventDefault();

 

var evt = document.createEvent("MouseEvents");

  evt.initMouseEvent("mousemove",

           true, //canBubble

           false, //cancelable

           window, //event's AbstractView : should be window 

           1, // detail : Event's mouse click count 

           e.screenX, // screenX

           e.screenY, // screenY

           e.clientX, // clientX

           e.clientY, // clientY

           e.ctrlKey, // ctrlKey

           e.altKey, // altKey

           e.shiftKey, // shiftKey

           e.metaKey, // metaKey 

           0, // button : 0 = click, 1 = middle button, 2 = right button  

           null // relatedTarget

 

);

mapdiv.dispatchEvent(evt);

 

}

 

mapcanvas.onmouseup = function(e){

e.preventDefault();

 

var evt = document.createEvent("MouseEvents");

  evt.initMouseEvent("mouseup",

           true, //canBubble

           false, //cancelable

           window, //event's AbstractView : should be window 

           1, // detail : Event's mouse click count 

           e.screenX, // screenX

           e.screenY, // screenY

           e.clientX, // clientX

           e.clientY, // clientY

           e.ctrlKey, // ctrlKey

           e.altKey, // altKey

           e.shiftKey, // shiftKey

           e.metaKey, // metaKey 

           0, // button : 0 = click, 1 = middle button, 2 = right button  

           null // relatedTarget

 

);

mapdiv.dispatchEvent(evt);

 

}

 

 

 

 

//drawImages();

drawRects();

//drawShapes();

</script>

</body>

</html>

 



как правильно передавать мышиные события из mapcanvas в mapdiv?

(чтобы карта ролировалась. pointer-events:none; не предлагать.)

окажите вспоможение!

14 комментариев
Всеволод Шмыров
20 ноября 2014, 19:05
Добрый вечер. А какую вы решаете задачу? Зачем эмулировать события клика на карту?

я рисую поверх карты на канве, но хочу чтобы события транслировались на карту через канву.

Всеволод Шмыров
21 ноября 2014, 11:08
Ваше решение плохо тем, что поддерживает только события мышки, в то время как может поступить события прикосновений. Система событий карты завязана на слой событий. Сверху есть элемент, который ловит события и через нашу систему событий передает ниже. В вашем случае будет правильней будет не просто наложить canvas поверх карты, а добавить canvas как слой или как pane. В таком случае ваш canvas окажется под слоем событий.
Первое решение можно посмотреть в модуле heatmap https://github.com/yandex/mapsapi-heatmap/blob/master/src/Heatmap.js

Просьба объяснить не почему моё решение плохое (прикосновения мне не нужны), а почему оно не работает???

Dom события передаются из канвы в div c картой

это абсолютно точно, а вот дальше ничего не происходит даже если делать что-то типа такого :

map.events.fire(e.type, {

type: e.type,

               target: map,

   position: [ e.clientX,  e.clientY]

}, map);

где ,map это объект Mapкстати событие dblclick прекрасно транслируется и работает а вот mousedown, mousemove, mouseup - нет, т.е. карта не ролируетсяКроме того я не хочу завязываться на структуру классов yandex maps и что-то там хачить, потому как собираюсь работать не только с яндекс картами, но и с google, OSM и т.д.и казалось бы что-может быть проще чем передать событие из одного div другому и ролировать карту.Или объясните тогда как взаимодействовать с вашим слоем событий?Бъюсь много часов над, казалось бы, простой вещью  и это сильно расстраивает...:(

 

Всеволод Шмыров
21 ноября 2014, 11:54
Потому что API карт слушает не только события контейнера карты.

Ну вам видней...и что из этого?

Тогда ответьте на вопрос:

почему работает dblclick (т.е меняется масштаб) и не работают mousedown, mousemove, mouseup

?

Всеволод Шмыров
21 ноября 2014, 12:29
Мы слушаем dblclick, для поведения драг используем события документа. Ваше решение плохо тем, что вам придется под каждой апи писать кучу условий, так как скорей всего у OSM и Google есть собственные особенности. Так или иначе сейчас вы завязываетесь на недокументированное поведение, которое не факт, что после очередного обновления не изменится.
Как я уже писал выше, правильней будет сделать отдельный слой. Этот совет так же нужно применить и к другим api.

Так и работа со слоями может измениться. разве нет?

Кроме того OSM и Google наверняка тоже по-разному работают со слоями. Какая выгода будет?

в принципе pointer-events:none; отлично бы подошло если бы не IE < 11

Проброс события на карту надо делать пробрасывая событие на карту.
А не пытаться собраться что-то ручками и как-то частями передавать.

var bullet = new ymaps.MapEvent({

                        type: event.get('type'),

                        target: map,

                        domEvent: event

}, map);

 

map.events.fire(event.get('type'), bullet);

 В коде предполагается что события случаются через ymaps.domEvent.manager.add(

ну да, так я тоже пытался делать:

(http://clubs.ya.ru/mapsapi/replies.xml?item_no=45513)

ymaps.domEvent.manager.add(mapdiv, [

 

            'mousedown',

            'mousemove',

            'mouseup',

            'wheel'

 

        ], function (e) {

 

            map.events.fire(e.type, new ymaps.MapEvent({

 

                type: e.type,

 

                target: map,

 

                position: e.position,

            

            }, map));

 

        });

и как-то не помогло

мне кажется, но с e.type и position: e.position вы немного ошиблись.

Я же просил передавать событие, а не его части

можно подробнее?

type: e.get('type'),

target: map,

domEvent: e

Посмотрел пример с Heatmap...

Насколько я понял там для каждого спота создается свой маленький canvas...

Мне же нужен большой канвас "накрывающий" карту.

Будут ли сообщения в этом случае работать нормально? т.е. будет ли ролироваться карта?  

И ещё... там везде используется canvas.toDataURL(), т.е. получается что не только на каждый спот создаётся канва, но и эта канва ещё и грабится в картинку, мне кажется что это очень долго и криво (по крайней мере для моего случая, в котором я собираюсь рисовать несколько тысяч объектов)

Переубедите меня!;-)