<!DOCTYPE html><head><meta charset="utf-8"><title>MapView</title>
<style>html,body,map-view{height:100%;margin:10px}</style>
</head><body>
<map-view type="google" key="..."></map-view>
<script type="module" src="./app.js" charset="uft-8"></script>
</body>
</html>
// app.js
import { MapView } from "./MapView.js";
MapView.define();
// MapView.js
import { MapProvider } from "./MapProvider.js";
import { Map } from "./Map.js";
export class MapView extends HTMLElement {
static get observedAttributes() {
return [ "key", "type", "width" ];
}
static define() {
customElements.define("map-view", MapView, { extends: "div" });
}
constructor() {
super();
this._map = null;
}
attr(name) { return this.getAttribute(name) || ""; }
connectedCallback() {
console.log("connectedCallback");
this._shadowRoot = this.attachShadow({ mode: "open" }); // { mode, host, innerHTML }
this._shadowRoot.innerHTML = MapView.template;
const div = this._shadowRoot.querySelector("div");
const type = this.attr("type");
const key = this.attr("key");
MapProvider.getContext(type).load(key).then(() => {
console.log("map script loaded");
this._map = new Map(div, {});
}).catch(err => {
console.error(err.message);
throw err;
});
}
disconnectedCallback() {
console.log("disconnectedCallback");
}
attributeChangedCallback(attributeName, oldValue, newValue, namespace) {
if (oldValue === null) {
console.log("attributeChangedCallback init", attributeName, oldValue, newValue, namespace);
} else if (oldValue !== null) {
console.log("attributeChangedCallback changed", attributeName, oldValue, newValue, namespace);
}
}
adoptedCallback() {
console.log("adoptedCallback");
}
static get template() {
const tempNode = document.querySelector("#map-view");
if (tempNode && tempNode.content) {
return tempNode.content.cloneNode(true);
}
return `
<style>
div { width: 100%; height: 100%; background-color: red; }
</style>
<div>
<slot></slot>
</div>
`;
}
};
// Map.js
export class Map {
constructor(parentNode, options) {
const mapTypeIds = [google.maps.MapTypeId.ROADMAP];
this._map = new google.maps.Map(parentNode, {
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: { lat: 35.658, lng: 139.702 },
zoom: 17,
minZoom: 4,
maxZoom: 20,
fullscreenControl: false,
zoomControlOptions: {
position: google.maps.ControlPosition.LEFT_BOTTOM,
},
streetViewControlOptions: {
position: google.maps.ControlPosition.LEFT_BOTTOM,
},
mapTypeControlOptions: {
position: google.maps.ControlPosition.TOP_RIGHT,
mapTypeIds: mapTypeIds,
},
scaleControl: true,
});
}
}
// MapsProvider.js
import { GoogleMapsProvider } from "./GoogleMapsProvider.js";
export class MapProvider {
static getContext(type = "") {
switch (type.toLowerCase()) {
case "google":
case "googlemap":
case "googlemaps":
return new GoogleMapsProvider();
case "":
throw new TypeError(`Need map-view type attribute`);
default:
throw new TypeError(`Unknown map-view type attribute: ${type}`);
}
}
}
// GoogleMapsProvider.js
export class GoogleMapsProvider {
constructor() {}
load(key) {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.onload = resolve;
script.onerror = reject;
script.id = "GoogleMapsProvider";
script.src = `//maps.googleapis.com/maps/api/js?key=${key}&v=3&language=jp`;
document.head.appendChild(script);
});
}
}