Unverified Commit 6a10a16f authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera Committed by GitHub
Browse files

Merge pull request #36 from vue-leaflet/l-icon

LIcon
parents aa7495a9 e393005e
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
<template>
  <div style="height: 50vh; width: 50vw;">
  <div style="height: 75vh; width: 50vw;">
    <l-map
      v-model="zoom"
      v-model:zoom="zoom"
@@ -15,11 +15,16 @@
          lol
        </l-tooltip>
      </l-marker>
      <l-marker :lat-lng="[47.41322, -1.219482]">
        <l-icon :icon-url="iconUrl" :icon-size="iconSize" />
      </l-marker>
    </l-map>
    <button @click="changeIcon">New kitten icon</button>
  </div>
</template>
<script>
import LMap from "./components/LMap.vue";
import LIcon from "./components/LIcon.vue";
import LTileLayer from "./components/LTileLayer.vue";
import LMarker from "./components/LMarker.vue";
import LControlLayers from "./components/LControlLayers.vue";
@@ -28,6 +33,7 @@ import LTooltip from "./components/LTooltip.vue";
export default {
  components: {
    LMap,
    LIcon,
    LTileLayer,
    LMarker,
    LControlLayers,
@@ -36,12 +42,28 @@ export default {
  data() {
    return {
      zoom: 2,
      iconWidth: 25,
      iconHeight: 40,
    };
  },
  computed: {
    iconUrl() {
      return `https://placekitten.com/${this.iconWidth}/${this.iconHeight}`;
    },
    iconSize() {
      return [this.iconWidth, this.iconHeight];
    },
  },
  methods: {
    log(a) {
      console.log(a);
    },
    changeIcon() {
      this.iconWidth += 2;
      if (this.iconWidth > this.iconHeight) {
        this.iconWidth = Math.floor(this.iconHeight / 2);
      }
    },
  },
};
</script>
+105 −0
Original line number Diff line number Diff line
<script>
import { onMounted, ref, inject, nextTick, h } from "vue";
import { propsBinder, remapEvents } from "../utils";
import { props } from "../functions/icon";

/**
 * Icon component, lets you add and custom icons to the map
 */
export default {
  name: "LIcon",
  props,
  setup(props, context) {
    const root = ref(null);

    const canSetParentHtml = inject("canSetParentHtml");
    const setParentHtml = inject("setParentHtml");
    const setIcon = inject("setIcon");

    let onDomEvent;
    let offDomEvent;
    let divIcon;
    let icon;
    let iconObject = undefined;

    const createIcon = (el, recreationNeeded, htmlSwapNeeded) => {
      const elHtml = el && el.innerHTML;
      if (!recreationNeeded) {
        if (htmlSwapNeeded && iconObject && canSetParentHtml()) {
          setParentHtml(elHtml);
        }
        return;
      }

      const listeners = remapEvents(context.attrs);
      if (iconObject) {
        offDomEvent(iconObject, listeners);
      }

      const options = {
        ...props,
      };

      if (elHtml) {
        options.html = elHtml;
      }

      iconObject = options.html ? divIcon(options) : icon(options);
      onDomEvent(iconObject, listeners);
      setIcon(iconObject);
    };

    const scheduleCreateIcon = () => {
      nextTick(() => createIcon(root.value, true, false));
    };

    const scheduleHtmlSwap = () => {
      nextTick(() => createIcon(root.value, false, true));
    };

    const methods = {
      setIconUrl: scheduleCreateIcon,
      setIconRetinaUrl: scheduleCreateIcon,
      setIconSize: scheduleCreateIcon,
      setIconAnchor: scheduleCreateIcon,
      setPopupAnchor: scheduleCreateIcon,
      setTooltipAnchor: scheduleCreateIcon,
      setShadowUrl: scheduleCreateIcon,
      setShadowRetinaUrl: scheduleCreateIcon,
      setShadowAnchor: scheduleCreateIcon,
      setBgPos: scheduleCreateIcon,
      setClassName: scheduleCreateIcon,
      setHtml: scheduleCreateIcon,
    };

    onMounted(async () => {
      const { DomEvent, divIcon: lDivIcon, icon: lIcon } = await import(
        "leaflet/dist/leaflet-src.esm"
      );

      onDomEvent = DomEvent.on;
      offDomEvent = DomEvent.off;
      divIcon = lDivIcon;
      icon = lIcon;

      propsBinder(methods, {}, props);

      const observer = new MutationObserver(scheduleHtmlSwap);
      observer.observe(root.value, {
        attributes: true,
        childList: true,
        characterData: true,
        subtree: true,
      });
      scheduleCreateIcon();
    });

    return { root };
  },
  render() {
    const content = this.$slots.default ? this.$slots.default() : undefined;

    return h("div", { ref: "root" }, content);
  },
};
</script>
+10 −1
Original line number Diff line number Diff line
<script>
import { onMounted, ref, h, inject } from "vue";
import { onMounted, ref, h, provide, inject } from "vue";
import {
  remapEvents,
  propsBinder,
@@ -22,6 +22,15 @@ export default {
    const addLayer = inject("addLayer");

    const latLng = provideLeafletWrapper("latLng");
    provide("canSetParentHtml", () => !!leafletRef.value.getElement());
    provide(
      "setParentHtml",
      (html) => (leafletRef.value.getElement().innerHTML = html)
    );
    provide(
      "setIcon",
      (newIcon) => leafletRef.value.setIcon && leafletRef.value.setIcon(newIcon)
    );
    const { options, methods } = markerSetup(props, leafletRef, context);

    onMounted(async () => {

src/functions/icon.js

0 → 100644
+67 −0
Original line number Diff line number Diff line
export const props = {
  iconUrl: {
    type: String,
    custom: true,
    default: null,
  },
  iconRetinaUrl: {
    type: String,
    custom: true,
    default: null,
  },
  iconSize: {
    type: [Object, Array],
    custom: true,
    default: null,
  },
  iconAnchor: {
    type: [Object, Array],
    custom: true,
    default: null,
  },
  popupAnchor: {
    type: [Object, Array],
    custom: true,
    default: () => [0, 0],
  },
  tooltipAnchor: {
    type: [Object, Array],
    custom: true,
    default: () => [0, 0],
  },
  shadowUrl: {
    type: String,
    custom: true,
    default: null,
  },
  shadowRetinaUrl: {
    type: String,
    custom: true,
    default: null,
  },
  shadowSize: {
    type: [Object, Array],
    custom: true,
    default: null,
  },
  shadowAnchor: {
    type: [Object, Array],
    custom: true,
    default: null,
  },
  bgPos: {
    type: [Object, Array],
    custom: true,
    default: () => [0, 0],
  },
  className: {
    type: String,
    custom: true,
    default: "",
  },
  options: {
    type: Object,
    custom: true,
    default: () => ({}),
  },
};