Skip to content

Commit

Permalink
Merge pull request #4357 from mind84/google_wmts
Browse files Browse the repository at this point in the history
[Feature] Add QMS Google Maps Tiles
  • Loading branch information
Gustry authored Jun 21, 2024
2 parents 4fec8cc + e592f4d commit 5f38e56
Show file tree
Hide file tree
Showing 9 changed files with 3,310 additions and 3 deletions.
78 changes: 77 additions & 1 deletion assets/src/modules/config/BaseLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const BaseLayerTypes = createEnum({
'WMTS': 'wmts',
'WMS': 'wms',
'Lizmap': 'lizmap',
'Google': 'google',
});

/**
Expand Down Expand Up @@ -309,6 +310,52 @@ export class BingBaseLayerConfig extends BaseLayerConfig {

}

const googleProperties = {
'title': { type: 'string' },
'mapType': { type: 'string' }
}

const googleOptionalProperties = {
'key': { type: 'string', nullable: true }
}

/**
* Class representing a Google base layer config
* @class
* @augments BaseLayerConfig
*/
export class GoogleBaseLayerConfig extends BaseLayerConfig {
/**
* Create a GOOGLE base layer config based on a config object
* @param {string} name - the base layer name
* @param {object} cfg - the lizmap config object for GOOGLE base layer
* @param {string} cfg.title - the base layer title
* @param {string} cfg.mapType - the base layer mapType
* @param {string} [cfg.key] - the base layer key
*/
constructor(name, cfg) {
if (!cfg || typeof cfg !== "object") {
throw new ValidationError('The cfg parameter is not an Object!');
}

if (Object.getOwnPropertyNames(cfg).length == 0) {
throw new ValidationError('The cfg parameter is empty!');
}

super(name, cfg, googleProperties, googleOptionalProperties)
this._type = BaseLayerTypes.Google;
}

/**
* The Google mapType
* @type {string}
*/
get mapType() {
return this._mapType;
}

}

const wmtsProperties = {
'title': { type: 'string' },
'url': { type: 'string' },
Expand Down Expand Up @@ -745,6 +792,18 @@ const QMSExternalLayer = {
"imagerySet": "Aerial",
"key": "",
},
"google-streets": {
"type" :"google",
"title": "Google Streets",
"mapType": "roadmap",
"key":""
},
"google-satellite": {
"type" :"google",
"title": "Google Satellite",
"mapType": "satellite",
"key":""
}
}

/**
Expand Down Expand Up @@ -839,7 +898,20 @@ export class BaseLayersConfig {
}
// add the apikey to the configuration
Object.assign(extendedCfg[layerTreeItem.name],{key:options["bingKey"]})
} else {
} else if (externalUrl && externalUrl.includes('google.com') && options["googleKey"]){
if (externalUrl.includes('lyrs=m')) {
// roads
extendedCfg[layerTreeItem.name] = structuredClone(QMSExternalLayer["google-streets"])
} else if (externalUrl.includes('lyrs=s')){
// fallback on satellite map
extendedCfg[layerTreeItem.name] = structuredClone(QMSExternalLayer["google-satellite"])
} else {
extendedCfg[layerTreeItem.name] = structuredClone(QMSExternalLayer["google-streets"])
}
// add the apikey to the configuration
Object.assign(extendedCfg[layerTreeItem.name],{key:options["googleKey"]})
}
else {
// layer could be converted to XYZ or WMTS background layers
extendedCfg[layerTreeItem.name] = structuredClone(layerTreeItem.layerConfig.externalAccess);
}
Expand Down Expand Up @@ -995,6 +1067,10 @@ export class BaseLayersConfig {
this._configs.push(new BingBaseLayerConfig(key, blCfg));
this._names.push(key);
break;
case BaseLayerTypes.Google:
this._configs.push(new GoogleBaseLayerConfig(key, blCfg));
this._names.push(key);
break;
case BaseLayerTypes.WMTS:
this._configs.push(new WmtsBaseLayerConfig(key, blCfg));
this._names.push(key);
Expand Down
6 changes: 5 additions & 1 deletion assets/src/modules/config/LayerTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,11 @@ function buildLayerTreeGroupConfigItems(wmsCapaLayerGroup, layersCfg, level) {
const groupItems = buildLayerTreeGroupConfigItems(wmsCapaLayer, layersCfg, level+1);
items.push(new LayerTreeGroupConfig(cfg.name, level+1, groupItems, wmsCapaLayer, cfg));
} else {
items.push(new LayerTreeLayerConfig(cfg.name, level+1, wmsCapaLayer, cfg));
// avoid to add the baseLayers group to the map if doesn't contains any layer.
if(wmsName.toLowerCase() != 'baselayers') {
items.push(new LayerTreeLayerConfig(cfg.name, level+1, wmsCapaLayer, cfg));
}

}
}
return items;
Expand Down
11 changes: 11 additions & 0 deletions assets/src/modules/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import TileGrid from 'ol/tilegrid/TileGrid.js';
import TileWMS from 'ol/source/TileWMS.js';
import XYZ from 'ol/source/XYZ.js';
import BingMaps from 'ol/source/BingMaps.js';
import Google from 'ol/source/Google.js';
import {BaseLayer as LayerBase} from 'ol/layer/Base.js';
import LayerGroup from 'ol/layer/Group.js';
import { Vector as VectorSource } from 'ol/source.js';
Expand Down Expand Up @@ -448,6 +449,16 @@ export default class map extends olMap {
// maxZoom: 19
}),
});
} else if (baseLayerState.type === BaseLayerTypes.Google) {
baseLayer = new TileLayer({
minResolution: layerMinResolution,
maxResolution: layerMaxResolution,
preload: Infinity,
source: new Google({
key: baseLayerState.key,
mapType: baseLayerState.mapType,
}),
});
} else if (baseLayerState.type === BaseLayerTypes.Lizmap) {
if (baseLayerState.layerConfig.cached) {
const parser = new WMTSCapabilities();
Expand Down
32 changes: 31 additions & 1 deletion assets/src/modules/state/BaseLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import EventDispatcher from './../../utils/EventDispatcher.js';
import { LayerConfig } from './../config/Layer.js';
import { AttributionConfig } from './../config/Attribution.js'
import { BaseLayerTypes, BaseLayersConfig, BaseLayerConfig, EmptyBaseLayerConfig, XyzBaseLayerConfig, BingBaseLayerConfig, WmtsBaseLayerConfig, WmsBaseLayerConfig } from './../config/BaseLayer.js';
import { BaseLayerTypes, BaseLayersConfig, BaseLayerConfig, EmptyBaseLayerConfig, XyzBaseLayerConfig, BingBaseLayerConfig, GoogleBaseLayerConfig, WmtsBaseLayerConfig, WmsBaseLayerConfig } from './../config/BaseLayer.js';
import { LayerVectorState, LayerRasterState, LayerGroupState, LayersAndGroupsCollection } from './Layer.js'
import { MapLayerLoadStatus } from './MapLayer.js';

Expand Down Expand Up @@ -267,6 +267,33 @@ export class BingBaseLayerState extends BaseLayerState {
}
}

/**
* Class representing a Google base layer state
* @class
* @augments BaseLayerState
*/
export class GoogleBaseLayerState extends BaseLayerState {
/**
* Create a base layers google state based on the google base layer config
* @param {GoogleBaseLayerConfig} baseLayerCfg - the lizmap google base layer config object
* @param {LayerRasterState} [itemState] - the lizmap google layer layer state
*/
constructor(baseLayerCfg, itemState = null ) {
if (baseLayerCfg.type !== BaseLayerTypes.Google) {
throw new TypeError('Not an `' + BaseLayerTypes.Google + '` base layer config. Get `' + baseLayerCfg.type + '` type for `' + baseLayerCfg.name + '` base layer!');
}
super(baseLayerCfg, itemState)
}

/**
* The google mapType
* @type {string}
*/
get mapType() {
return this._baseLayerConfig.mapType;
}
}

/**
* Class representing an WMTS base layer state
* @class
Expand Down Expand Up @@ -432,6 +459,9 @@ export class BaseLayersState extends EventDispatcher {
case BaseLayerTypes.Bing:
this._baseLayersMap.set(blConfig.name, new BingBaseLayerState(blConfig, itemState));
break;
case BaseLayerTypes.Google:
this._baseLayersMap.set(blConfig.name, new GoogleBaseLayerState(blConfig, itemState));
break;
case BaseLayerTypes.WMTS:
this._baseLayersMap.set(blConfig.name, new WmtsBaseLayerState(blConfig, itemState));
break;
Expand Down
39 changes: 39 additions & 0 deletions tests/end2end/playwright/google-basemap.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

const { test, expect } = require('@playwright/test');
const { gotoMap } = require('./globals');

test.describe('Google Maps Baselayers', () => {
test('Load map with no API Key', async ({ page }) => {
const url = '/index.php/view/map?repository=testsrepository&project=google_basemap';
await gotoMap(url, page);

// baselayers group should be hidden since it is empty due to the default STRICT_GOOGLE_TOS_CHECK env variable value = TRUE
await expect(page.locator('#switcher-baselayer.hide')).toHaveCount(1);

});

test('Load map with dummy API Key', async ({ page }) => {
// listen to the requests to intercept failing ones
let initGoogleRequestsCount = 0;
page.on('response', response => {
if(response.url().includes('createSession?key=dummy') && response.status() != 200) {
initGoogleRequestsCount++;
}
});

const url = '/index.php/view/map?repository=testsrepository&project=google_apikey_basemap';
await gotoMap(url, page);

// there are three Google base layers in the project, so the expected number of failing requests is three
expect(initGoogleRequestsCount).toBe(3);
// baselayers group should be visible...
await expect(page.locator('#switcher-baselayer')).toBeVisible();

//.. and should contains the three Google base layers (not loaded)
let options = page.locator('#switcher-baselayer').getByRole('combobox').locator('option');
await expect(options).toHaveCount(3);
expect(await options.nth(0).getAttribute('value')).toBe('Google Streets');
expect(await options.nth(1).getAttribute('value')).toBe('Google Satellite');
expect(await options.nth(2).getAttribute('value')).toBe('Google Hybrid');
});
});
Loading

2 comments on commit 5f38e56

@3liz-bot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latest weekly run of end2end "playwright" tests failed with this latest commit on the branch release_3_6 😣

CC @nboisteault and @Gustry, please have a look to the logs. Maybe it's a false positive ?

Visit https://github.com/3liz/lizmap-web-client/actions/runs/9639019612

@3liz-bot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latest weekly run of end2end "cypress" tests failed with this latest commit on the branch release_3_6 😣

CC @nboisteault and @Gustry, please have a look to the logs. Maybe it's a false positive ?

Visit https://github.com/3liz/lizmap-web-client/actions/runs/9639019612

Please sign in to comment.