added image map support
This commit is contained in:
parent
257fb94bc0
commit
43b9a6b39f
@ -15,8 +15,8 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { Observable, Subject } from 'rxjs';
|
import { Observable, Subject, from, fromEvent, of } from 'rxjs';
|
||||||
import { finalize, share } from 'rxjs/operators';
|
import { finalize, share, map } from 'rxjs/operators';
|
||||||
import base64js from 'base64-js';
|
import base64js from 'base64-js';
|
||||||
|
|
||||||
export function onParentScrollOrWindowResize(el: Node): Observable<Event> {
|
export function onParentScrollOrWindowResize(el: Node): Observable<Event> {
|
||||||
@ -221,6 +221,18 @@ function scrollParents(node: Node): Node[] {
|
|||||||
return scrollParentNodes;
|
return scrollParentNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hashCode(str) {
|
||||||
|
var hash = 0;
|
||||||
|
var i, char;
|
||||||
|
if (str.length == 0) return hash;
|
||||||
|
for (i = 0; i < str.length; i++) {
|
||||||
|
char = str.charCodeAt(i);
|
||||||
|
hash = ((hash << 5) - hash) + char;
|
||||||
|
hash = hash & hash; // Convert to 32bit integer
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
function easeInOut(
|
function easeInOut(
|
||||||
currentTime: number,
|
currentTime: number,
|
||||||
startTime: number,
|
startTime: number,
|
||||||
@ -411,3 +423,27 @@ export function snakeCase(name: string, separator: string): string {
|
|||||||
export function getDescendantProp(obj: any, path: string): any {
|
export function getDescendantProp(obj: any, path: string): any {
|
||||||
return path.split('.').reduce((acc, part) => acc && acc[part], obj);
|
return path.split('.').reduce((acc, part) => acc && acc[part], obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function imageLoader(imageUrl: string): Observable<HTMLImageElement>{
|
||||||
|
const image = new Image();
|
||||||
|
const imageLoad$ = fromEvent(image, 'load').pipe(map(event=>image));
|
||||||
|
image.src = imageUrl;
|
||||||
|
return imageLoad$;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageAspectMap = {};
|
||||||
|
|
||||||
|
export function aspectCache(imageUrl: string): Observable<number>{
|
||||||
|
if(imageUrl?.length){
|
||||||
|
const hash = hashCode(imageUrl);
|
||||||
|
let aspect = imageAspectMap[hash];
|
||||||
|
if(aspect){
|
||||||
|
return of(aspect);
|
||||||
|
}
|
||||||
|
else return imageLoader(imageUrl).pipe(map(image=>{
|
||||||
|
aspect = image.width/image.height;
|
||||||
|
imageAspectMap[hash] = aspect;
|
||||||
|
return aspect;
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,11 +12,11 @@ export default class LeafletMap {
|
|||||||
markers = [];
|
markers = [];
|
||||||
tooltips = [];
|
tooltips = [];
|
||||||
map: L.Map;
|
map: L.Map;
|
||||||
options;
|
options: MapOptions;
|
||||||
isMarketCluster;
|
isMarketCluster;
|
||||||
|
|
||||||
|
|
||||||
constructor($container, options: MapOptions) {
|
constructor($container: HTMLElement, options: MapOptions) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,6 +105,10 @@ export default class LeafletMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onResize(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
getTooltips() {
|
getTooltips() {
|
||||||
return this.tooltips;//rewrite
|
return this.tooltips;//rewrite
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ export interface MapOptions {
|
|||||||
disableScrollZooming?: boolean,
|
disableScrollZooming?: boolean,
|
||||||
minZoomLevel?: number,
|
minZoomLevel?: number,
|
||||||
mapProvider: MapProviders,
|
mapProvider: MapProviders,
|
||||||
|
mapUrl?: string;
|
||||||
credentials?: any, // declare credentials format
|
credentials?: any, // declare credentials format
|
||||||
defaultCenterPosition?: L.LatLngExpression,
|
defaultCenterPosition?: L.LatLngExpression,
|
||||||
markerClusteringSetting?
|
markerClusteringSetting?
|
||||||
|
|||||||
@ -3,8 +3,7 @@ import LeafletMap from './leaflet-map';
|
|||||||
import { deepClone } from '@core/utils';
|
import { deepClone } from '@core/utils';
|
||||||
import { openstreetMapSettingsSchema, googleMapSettingsSchema, imageMapSettingsSchema, tencentMapSettingsSchema, hereMapSettingsSchema, commonMapSettingsSchema, routeMapSettingsSchema, markerClusteringSettingsSchema, markerClusteringSettingsSchemaGoogle, markerClusteringSettingsSchemaLeaflet } from './schemes';
|
import { openstreetMapSettingsSchema, googleMapSettingsSchema, imageMapSettingsSchema, tencentMapSettingsSchema, hereMapSettingsSchema, commonMapSettingsSchema, routeMapSettingsSchema, markerClusteringSettingsSchema, markerClusteringSettingsSchemaGoogle, markerClusteringSettingsSchemaLeaflet } from './schemes';
|
||||||
import { MapWidgetStaticInterface, MapWidgetInterface } from './map-widget.interface';
|
import { MapWidgetStaticInterface, MapWidgetInterface } from './map-widget.interface';
|
||||||
import { OpenStreetMap, TencentMap } from './providers';
|
import { OpenStreetMap, TencentMap, ImageMap, GoogleMap } from './providers';
|
||||||
import { GoogleMap } from './providers/google-map';
|
|
||||||
|
|
||||||
const providerSets = {
|
const providerSets = {
|
||||||
'openstreet-map': {
|
'openstreet-map': {
|
||||||
@ -18,6 +17,10 @@ const providerSets = {
|
|||||||
'google-map': {
|
'google-map': {
|
||||||
MapClass: GoogleMap,
|
MapClass: GoogleMap,
|
||||||
schema: googleMapSettingsSchema
|
schema: googleMapSettingsSchema
|
||||||
|
},
|
||||||
|
'image-map': {
|
||||||
|
MapClass: ImageMap,
|
||||||
|
schema: imageMapSettingsSchema
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,6 +31,8 @@ TbMapWidgetV2 = class TbMapWidgetV2 implements MapWidgetInterface {
|
|||||||
schema;
|
schema;
|
||||||
|
|
||||||
constructor(mapProvider: MapProviders, drawRoutes, ctx, useDynamicLocations, $element, isEdit) {
|
constructor(mapProvider: MapProviders, drawRoutes, ctx, useDynamicLocations, $element, isEdit) {
|
||||||
|
console.log(ctx.settings);
|
||||||
|
|
||||||
// if(!$element) return
|
// if(!$element) return
|
||||||
if (!$element) {
|
if (!$element) {
|
||||||
$element = ctx.$container[0];
|
$element = ctx.$container[0];
|
||||||
@ -40,11 +45,11 @@ TbMapWidgetV2 = class TbMapWidgetV2 implements MapWidgetInterface {
|
|||||||
disableScrollZooming: false,
|
disableScrollZooming: false,
|
||||||
minZoomLevel: drawRoutes ? 18 : 15,
|
minZoomLevel: drawRoutes ? 18 : 15,
|
||||||
mapProvider: mapProvider,
|
mapProvider: mapProvider,
|
||||||
|
mapUrl: ctx?.settings?.mapImageUrl,
|
||||||
credentials: '',
|
credentials: '',
|
||||||
defaultCenterPosition: [0, 0],
|
defaultCenterPosition: [0, 0],
|
||||||
markerClusteringSetting: null
|
markerClusteringSetting: null
|
||||||
}
|
}
|
||||||
console.log("TCL: TbMapWidgetV2 -> constructor -> providerSets[mapProvider]",mapProvider)
|
|
||||||
let MapClass = providerSets[mapProvider]?.MapClass;
|
let MapClass = providerSets[mapProvider]?.MapClass;
|
||||||
if(!MapClass){
|
if(!MapClass){
|
||||||
//delete this;
|
//delete this;
|
||||||
@ -62,7 +67,8 @@ TbMapWidgetV2 = class TbMapWidgetV2 implements MapWidgetInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onResize() {
|
onResize() {
|
||||||
}
|
this.map.onResize();//not work
|
||||||
|
}
|
||||||
|
|
||||||
getSettingsSchema(): Object {
|
getSettingsSchema(): Object {
|
||||||
return this.schema;
|
return this.schema;
|
||||||
@ -70,6 +76,7 @@ TbMapWidgetV2 = class TbMapWidgetV2 implements MapWidgetInterface {
|
|||||||
|
|
||||||
resize() {
|
resize() {
|
||||||
this.map?.invalidateSize();
|
this.map?.invalidateSize();
|
||||||
|
this.map.onResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static dataKeySettingsSchema(): Object {
|
public static dataKeySettingsSchema(): Object {
|
||||||
|
|||||||
@ -0,0 +1,112 @@
|
|||||||
|
import L from 'leaflet';
|
||||||
|
import LeafletMap from '../leaflet-map';
|
||||||
|
import { MapOptions } from '../map-models';
|
||||||
|
import { aspectCache } from '@app/core/utils';
|
||||||
|
|
||||||
|
const maxZoom = 4;//?
|
||||||
|
|
||||||
|
export class ImageMap extends LeafletMap {
|
||||||
|
|
||||||
|
imageOverlay;
|
||||||
|
aspect = 0;
|
||||||
|
width = 0;
|
||||||
|
height = 0;
|
||||||
|
|
||||||
|
constructor(private $container: HTMLElement, options: MapOptions) {
|
||||||
|
super($container, options);
|
||||||
|
aspectCache(options.mapUrl).subscribe(aspect => {
|
||||||
|
this.aspect = aspect;
|
||||||
|
this.onResize();
|
||||||
|
super.setMap(this.map);
|
||||||
|
super.initSettings(options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateBounds(updateImage?, lastCenterPos?) {
|
||||||
|
const w = this.width;
|
||||||
|
const h = this.height;
|
||||||
|
let southWest = this.pointToLatLng(0, h);
|
||||||
|
let northEast = this.pointToLatLng(w, 0);
|
||||||
|
const bounds = new L.LatLngBounds(southWest, northEast);
|
||||||
|
|
||||||
|
if (updateImage && this.imageOverlay) {
|
||||||
|
this.imageOverlay.remove();
|
||||||
|
this.imageOverlay = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.imageOverlay) {
|
||||||
|
this.imageOverlay.setBounds(bounds);
|
||||||
|
} else {
|
||||||
|
this.imageOverlay = L.imageOverlay(this.options.mapUrl, bounds).addTo(this.map);
|
||||||
|
|
||||||
|
}
|
||||||
|
const padding = 200 * maxZoom;
|
||||||
|
southWest = this.pointToLatLng(-padding, h + padding);
|
||||||
|
northEast = this.pointToLatLng(w + padding, -padding);
|
||||||
|
const maxBounds = new L.LatLngBounds(southWest, northEast);
|
||||||
|
this.map.setMaxBounds(maxBounds);
|
||||||
|
if (lastCenterPos) {
|
||||||
|
lastCenterPos.x *= w;
|
||||||
|
lastCenterPos.y *= h;
|
||||||
|
/* this.ctx.$scope.$injector.get('$mdUtil').nextTick(() => {
|
||||||
|
this.map.panTo(center, { animate: false });
|
||||||
|
});*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onResize(updateImage?) {
|
||||||
|
let width = this.$container.clientWidth;
|
||||||
|
if (width > 0 && this.aspect) {
|
||||||
|
let height = width / this.aspect;
|
||||||
|
const imageMapHeight = this.$container.clientHeight;
|
||||||
|
if (imageMapHeight > 0 && height > imageMapHeight) {
|
||||||
|
height = imageMapHeight;
|
||||||
|
width = height * this.aspect;
|
||||||
|
}
|
||||||
|
width *= maxZoom;
|
||||||
|
const prevWidth = this.width;
|
||||||
|
const prevHeight = this.height;
|
||||||
|
if (this.width !== width) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = width / this.aspect;
|
||||||
|
if (!this.map) {
|
||||||
|
this.initMap(updateImage);
|
||||||
|
} else {
|
||||||
|
const lastCenterPos = this.latLngToPoint(this.map.getCenter());
|
||||||
|
lastCenterPos.x /= prevWidth;
|
||||||
|
lastCenterPos.y /= prevHeight;
|
||||||
|
this.updateBounds(updateImage, lastCenterPos);
|
||||||
|
this.map.invalidateSize(true);
|
||||||
|
// this.updateMarkers();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initMap(updateImage?) {
|
||||||
|
if (!this.map && this.aspect > 0) {
|
||||||
|
var center = this.pointToLatLng(this.width / 2, this.height / 2);
|
||||||
|
this.map = L.map(this.$container, {
|
||||||
|
minZoom: 1,
|
||||||
|
maxZoom: maxZoom,
|
||||||
|
scrollWheelZoom: !this.options.disableScrollZooming,
|
||||||
|
center: center,
|
||||||
|
zoom: 1,
|
||||||
|
crs: L.CRS.Simple,
|
||||||
|
attributionControl: false
|
||||||
|
});
|
||||||
|
this.updateBounds(updateImage);
|
||||||
|
// this.updateMarkers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pointToLatLng(x, y) {
|
||||||
|
return L.CRS.Simple.pointToLatLng({ x, y } as L.PointExpression, maxZoom - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
latLngToPoint(latLng) {
|
||||||
|
return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,4 @@
|
|||||||
export * from './tencent-map';
|
export * from './tencent-map';
|
||||||
|
export * from './google-map';
|
||||||
|
export * from './image-map';
|
||||||
export * from './openstreet-map';
|
export * from './openstreet-map';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user