【问题标题】:Leaflet open popup on mouse hover over list将鼠标悬停在列表上时传单打开弹出窗口
【发布时间】:2019-01-31 01:36:56
【问题描述】:

我的应用程序的一个视图是,一侧是所有引脚的列表,另一侧是带有实际引脚的地图。

我希望在用鼠标悬停在列表中时打开弹出窗口。假设我的鼠标在列表中的 #1 上,我希望打开相应引脚的弹出窗口。

这是来自列表组件的 html:

    <table class="table-striped">
      <thead>
        <!-- <th>id</th> -->
        <th>Kunstwerkname</th>
        <th>Strasse</th>
        <th>PLZ</th>
        <th>
          <button class="button-list" (click)="addArtwork()">
            <img src="assets/icons/add.svg">
          </button>
        </th>
      </thead>
      <tbody>
        <tr *ngFor="let artwork of artworkList;" class="artworkList" (mouseover)="previewPopup(artwork)">
          <td>{{artwork.name}}</td>
          <td>{{artwork.streetname}}</td>
          <td>{{artwork.zipcode}}</td>
          <td>
            <button class="button-list" (click)="editArtwork(artwork)">
              <img src="assets/icons/edit.svg">
            </button>
            <button class="button-list" (click)="deleteArtwork(artwork)">
              <img src="assets/icons/delete.svg">
            </button>
          </td>
        </tr>
      </tbody>
    </table>

列表组件的ts:

import { Artwork, ArtworkService } from './../_services/artwork.service';
import { Component, OnInit, Output, EventEmitter } from '@angular/core';


@Component({
  selector: 'app-artwork-list',
  templateUrl: './artwork-list.component.html',
  styleUrls: ['./artwork-list.component.css']
})
export class ArtworkListComponent implements OnInit {
  @Output() private add = new EventEmitter();
  @Output() private edit = new EventEmitter<number>();
  @Output() private preview = new EventEmitter<number>();
  artworkList: Artwork[];

  constructor(
    private artworkService: ArtworkService,
) { }

  ngOnInit() {
    this.refresh();
  }
  refresh() {
    this.artworkService.retrieveAll().then(
      artworkList => this.artworkList = artworkList
    );
  }

  addArtwork() {
    console.log('add artwork');
    this.add.emit();
  }

  editArtwork(artwork: Artwork) {
    console.log('edit artwork ' + artwork.name + ' ' + artwork.id );
    this.edit.emit(artwork.id);
  }

  deleteArtwork(artwork: Artwork) {
    console.log('delete artwork ' + artwork.name + ' ' + artwork.id );
    this.artworkService.delete(artwork.id).then(
      () => this.refresh()
    );
  }

  previewPopup(artwork: Artwork) {
    console.log("hovering mouse");
    console.log(artwork.id);
    this.preview.emit(artwork.id);
  }

}

和地图组件的ts:

import { Component, OnInit, Output, EventEmitter, ElementRef, Input } from '@angular/core';

/*When you include the leaflet script inside the Angular project, it gets
loaded and exported into a L variable.*/
declare let L; //this is the leaflet variable!

import { MapButtonsComponent } from './map-buttons/map-buttons';
import { Artwork, ArtworkService } from '../_services/artwork.service';
import { FilterMapComponent } from './filter-map/filter-map.component';



@Component({
  selector: 'app-open-street-map',
  templateUrl: './open-street-map.component.html',
  styleUrls: ['./open-street-map.component.css']
})
export class OpenStreetMapComponent implements OnInit {
  @Output() private add = new EventEmitter();
  @Output() private edit = new EventEmitter<number>();
  artworkList: Artwork[];
  map;

  // markerIcon
  markerIcon = {
    icon: L.icon({
      iconSize: [25, 41],
      iconAnchor: [13, 16],
      iconUrl: 'assets/icons/marker.svg',
      shadowUrl: 'assets/icons/marker-shadow.png'
    })
  };

  constructor(
    private artworkService: ArtworkService,
    private elementRef: ElementRef
  ) { }

  ngOnInit() {
    this.map = L.map('map', {
      center: [48.208, 16.373],
      zoom: 13,
      zoomControl: false,
    });

    this.refresh();

    // base layer
    L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
      attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
      maxZoom: 18,
      minZoom: 13,
      id: 'mapbox.streets',
      accessToken: 'pk.eyJ1IjoicHcxN2wwMDgiLCJhIjoiY2pua2c2OWxuMGVkOTNxbWh5MWNqajEwdyJ9.X_SuGwNGs12TwCsrsUvBxw'
    }).addTo(this.map);

    MapButtonsComponent.renderZoom(this.map);
    MapButtonsComponent.renderCompass(this.map);
    MapButtonsComponent.renderLocation(this.map);
  }

  previewArtwork() {
   this.map.eachLayer(layer => {
  if (layer instanceof L.Marker) {
    this.map.removeLayer(layer);
  }
});
let previewedMarker = L.marker([artwork.latitude, artwork.longitude], this.markerIcon)
  .addTo(this.map)
  .on('mouseover', () => {
    openPopup();
  });
}

  }
}

【问题讨论】:

  • 创建指令怎么样?
  • 是传单问题还是角度问题?你知道怎么只用传单吗?
  • @YaFred 我猜解决方案/问题包括两者!是的,使用传单只需添加“鼠标悬停”而不是“单击”即可打开弹出窗口,但这特别适用于鼠标在标记上的情况。我想要实现的是,弹出窗口在屏幕左侧的列表上方打开。右边是带有标记的地图,左边是标记列表。我希望当我将鼠标悬停在列表上时,相应的标记会打开它们的弹出窗口。我希望我已经把它表达到一个可以理解的范围内。

标签: javascript angular typescript popup leaflet


【解决方案1】:

可以考虑以下方法。让我们假设标记的初始数据以以下格式表示:

locations = [
    {
      name: "Oslo",
      lat: 59.923043,
      lng: 10.752839
    },
    {
      name: "Stockholm",
      lat: 59.339025,
      lng: 18.065818
    },
    //..
  ];

那么对于地图上给定的数据标记可以这样初始化:

this.markers = this.locations.map(loc => {
    const marker = new L.marker({ lat: loc.lat, lng: loc.lng });
    marker.bindPopup(loc.name);
    marker.addTo(map);
    return marker;
}); 

现在轮到选择器组件和地图本身之间的通信了,让我们假设以下选择器:

<ul>
  <li (mouseenter) ="mouseEnter(idx) "  (mouseleave) ="mouseLeave(idx)"  *ngFor="let loc of locations; let idx = index">{{ loc.name }}</li>
</ul>

然后可以像这样控制弹出窗口的可见性:

mouseEnter(selectedIndex) {
   const selectedMarker = this.markers[selectedIndex];
  selectedMarker.openPopup();
}

mouseLeave(selectedIndex) {
   const selectedMarker = this.markers[selectedIndex];
   selectedMarker.closePopup();
}

Here is a demo

【讨论】:

  • 我不断收到错误“selectedMarker.openPopup 不是函数”,有什么想法吗?我已经调整了您的解决方案以适应我的应用程序。唯一的区别是,索引从我的列表组件传递到我的地图组件,然后像您所做的那样传递到标记数组。但我一直收到这个错误,不知道如何继续!
  • @kontenurban,我只能在没有看到实际代码的情况下猜测,但错误可能意味着 1)index 无效或 2)this.markers[selectedIndex] 在您的情况下不是标记对象跨度>
【解决方案2】:

你必须听mouseentermouseleave而不是使用mouseover

mouseenter,您将创建一个弹出窗口并将其放置在地图上,在mouseleave,您将关闭弹出窗口

带有 jQ​​uery 的示例代码(我的 postContent 等同于您的作品)

$("div.postContent").on("mouseenter", function(e) {
        var postId = $(this).attr("data-postId");

        tooltipPopup = L.popup();   
        var title = postlistByGlobalId[postId].title;
        tooltipPopup.setContent(title);
        tooltipPopup.setLatLng(markersByGlobalId[postId].getLatLng());
        tooltipPopup.openOn(map);

        $(this).addClass('hover');
    });

$("div.postContent").on("mouseleave", function(e) {
        $(this).removeClass('hover');
        map.closePopup(tooltipPopup);
    });

要实现这一点,您需要为所有艺术品提供一个唯一的 ID(在我的示例中为 postId),并将您的标记放入关联数组 markersByGlobalId

这可能很有用:http://franceimage.github.io/maphttp://franceimage.github.io/map-v1

我的示例是单一的(1 个 html,1 个 js 文件)。你需要做一些额外的工作才能在你的 Angular 应用中使用它。

【讨论】:

    猜你喜欢
    • 2022-12-19
    • 2014-05-14
    • 1970-01-01
    • 2016-09-23
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    • 1970-01-01
    • 2011-04-18
    相关资源
    最近更新 更多