如何使用传单js在地图上精确放置div元素? [英] How to precisely place a div element on a map using leaflet js?

查看:102
本文介绍了如何使用传单js在地图上精确放置div元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试了这几种方法,但未能使其正常工作。我想在多个时区内将时钟放在地图的顶部。我有一个用于创建时钟的javascript,我将时钟放在 div 元素中。



以下是我的尝试:


  1. 用<$ c创建一个点$ c> 0,0 coordinates。

  2. 从这一点开始,使用 containerPointToLatLng

  3. 创建 LatLng 使用上面的lat和long为时区。

  4. 将此 LatLng 转换为Point,然后从此处使用 x,y 定位div元素。

我首先渲染页面然后在body调整大小时执行逻辑。但是,如果我更改浏览器窗口的大小,则时钟位置不正确。



有任何建议吗?

解决方案

要回答OP的精确问题,即在调整浏览器窗口大小时如何重新定位时钟(因此地图容器尺寸可能已经改变),人们应该重新计算地图上的时钟位置



现场演示: http://plnkr.co/edit/ V2pvcva5S9OZ2N7LlI8r?p =预览


I have tried this couple of ways but have not been able to get it working. I want to place clocks at the top of the map within multiple timezones. I have a the javascript to create the clock and I place the clock in a div element.

Here is what I tried:

  1. Create a Point with 0,0 coordinates.
  2. From this point get the latitude value for the top of the map using containerPointToLatLng.
  3. Create LatLng using the above lat and long for the timezone.
  4. Converted this LatLng to Point and then positioning the div element with the x,y from this point.

I execute the logic both when the page is first rendered and then on body resize. However, if I change the size of the browser window, the clock does not position correctly.

Any suggestions?

解决方案

To answer OP's precise issue, i.e. how to re-position the clock when the browser window is resized (hence map container dimensions may have changed), one should probably just re-compute the clock position on map's "resize" event.

However, it is not clear whether OP placed the clock as a child of the map container, or somewhere else on the page DOM tree.

It is probably much easier to place it as a child of the map, so that its position is always relative to the map container.

What OP originally asked?

If I understand correctly the original desired result, the OP would like to overlay a clock (or whatever information) on top of a particular geographical position (Toronto city in that case [UTC -5], according to comments).

However, the information container should not lay at a basemap fixed position, i.e. not at a precise geographic coordinated point (like a marker or a popup would), but at the top of the map container, similarly to a Control (hence iH8's original answer).

Except that it should not be totally fixed within the map container, but horizontally move with the city (or whatever specified geographical coordinates). Hence OP's comment to iH8's answer.

Therefore it sounds like something similar to that site, except with an interactive (navigate-able) map and the "UTC-5" header replaced by a clock (or whatever information, hence an HTML container should do it) and horizontally following Toronto.

Put differently, the clock should sit at a particular vertical line, i.e. longitude / meridian.

Unfortunately, even 2 years and a half after the question is posted, there is still no Leaflet plugin that provides such functionality (at least within Leaflet plugins page).

Extending the use case to highly zoomed-in map…

That being said, and given the fact that the user may be able to zoom highly into the city (OP did not specify the maximum zoom level), it might not be a very good user experience having that clock horizontally follow a precise longitude: for example, it could track Toronto centroid / city hall / whatever particular place, and when user is zoomed-in at another city district, the clock is no longer visible, whereas he/she is still viewing a part of Toronto city…

To extend that use case, the clock should very probably be visible in whatever area it applies, i.e. as soon as the map view port intersects the associated time zone.

Extending the use case to highly zoomed-out map…

Another point not detailed by OP, is what to do when places of different time zones are visible in the map view port? In the above mentioned site, we have one header per visible time zone, which seems the most complete information we can get.

But since Leaflet allows to zoom out down to level 0, where the entire world (i.e. essentially 24 time zones / actually 39 according to Wikipedia, not including potential effect of Daylight Saving Time - DST) is represented with a 256 pixels width, there is little room to fit all these clocks, if each one must be vertically aligned with its associated time zone.

For now let's assume we do not care if clocks overlap.

Even more custom case…

But OP may have wished to display the clock only for particular places, not for the entire world. OP did not even say that clocks would be different (we could have clocks for cities in the same time zone, even though it could be more interesting to have these clocks sit next to their city - even on par with their latitude, so that it is easier to spot which city the clock is associated to, like in the case of 2 cities on the same meridian; but in that case, a marker with L.divIcon would be enough).

Hence a custom case would be not to consider official time zones, but developer's specified areas.

So we forget about the latitude and try to align a clock vertically above the area, as long as it intersects the map view port.

Describing a generic solution

Therefore it sounds like a generic solution would be to enable the application developer to specify an array of HTML Elements, each one associated with a range of longitudes (could also be an area / polygon).

The time zones use case would then be a particular case where the specified areas are simply those from the time zones.

Then, each Element should be visible if and only if its associated area intersects the view port (therefore we introduce a possibility to hide it when the latitude range is out of view).

As for positioning, let's choose:

  • By the top of the map container (similar to a Control), as mentioned by OP.
  • Horizontally centered within the intersection of the view port and of the associated area.

HTML:

<div id="map"></div>

<div id="clockToronto" class="clock leaflet-control">Clock here for Toronto</div>
<div id="clockBurlington" class="clock leaflet-control">Clock here for Burlington</div>

CSS:

.clock {
  width: 150px;
  text-align: center;
  position: absolute;
  border: 1px solid black;
}

#clockToronto {
  background-color: yellow;
}

#clockBurlington {
  background-color: orange;
}

JavaScript:

var map = L.map("map").setView([43.7, -79.4], 10);

// Application specific.
var clockTorontoElement = L.DomUtil.get("clockToronto"),
    clockBurlingtonElement = L.DomUtil.get("clockBurlington"),
    zones = [
      {
        element: clockTorontoElement, // Using the HTML Element for now.
        width: parseInt(window.getComputedStyle(clockTorontoElement, null).getPropertyValue("width"), 10),
        area: L.latLngBounds([43.58, -79.64], [43.86, -79.10]) // Using L.latLngBounds for now.
      },
      {
        element: clockBurlingtonElement, // Using the HTML Element for now.
        width: parseInt(window.getComputedStyle(clockBurlingtonElement, null).getPropertyValue("width"), 10),
        area: L.latLngBounds([43.28, -79.96], [43.48, -79.71]) // Using L.latLngBounds for now.
      }
    ];

// Initialization
var controlsContainer = map._container.getElementsByClassName("leaflet-control-container")[0],
    firstCorner = controlsContainer.firstChild,
    mapContainerWidth;

map.on("resize", setMapContainerWidth);
setMapContainerWidth();

// Applying the zones.
for (var i = 0; i < zones.length; i += 1) {
  setZone(zones[i]);
}

function setZone(zoneData) {
  // Visualize the area.
  L.rectangle(zoneData.area).addTo(map);
  console.log("width: " + zoneData.width);

  controlsContainer.insertBefore(zoneData.element, firstCorner);
  map.on("move resize", function () {
    updateZone(zoneData);
  });
  updateZone(zoneData);
}

function updateZone(zoneData) {
  var mapBounds = map.getBounds(),
      zoneArea = zoneData.area,
      style = zoneData.element.style;

  if (mapBounds.intersects(zoneArea)) {
    style.display = "block";

    var hcenterLng = getIntersectionHorizontalCenter(mapBounds, zoneArea),
        hcenter = isNaN(hcenterLng) ? 0 : map.latLngToContainerPoint([0, hcenterLng]).x;

    // Update Element position.
    // Could be refined to keep the entire Element visible, rather than cropping it.
    style.left = (hcenter - (zoneData.width / 2)) + "px";
  } else {
    style.display = "none";
  }
}

function getIntersectionHorizontalCenter(bounds1, bounds2) {
  var west1 = bounds1.getWest(),
      west2 = bounds2.getWest(),
      westIn = west1 < west2 ? west2 : west1,
      east1 = bounds1.getEast(),
      east2 = bounds2.getEast(),
      eastIn = east1 < east2 ? east1 : east2;

  return (westIn + eastIn) / 2;
}

function setMapContainerWidth() {
  mapContainerWidth = map.getSize().x;
}

Live demo: http://plnkr.co/edit/V2pvcva5S9OZ2N7LlI8r?p=preview

这篇关于如何使用传单js在地图上精确放置div元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆