BaseDynamicLayer.createSubclass(...) build error in 4.19
Hi there,
Recently we are working on upgrade @arcgis/webpack-plugin from 4.15 to 4.19. As Esri support suggested, we have switch to use ES modules from arcgis-js-api. Instead use arcgis/core.
But after we do npm install, and when I compile our tS code by npm run build, I get the following build errors: error TS2339: Property 'createSubclass' does not exist on type 'BaseDynamicLayerConstructor'.
I have discuss with Esri support many times about this, they could not find out why I have this error. Even the sample code they give to me also use BaseDynamicLayerConstructor.createSubclass. And the sample code is html code. • https://github.com/Esri/jsapi-resources/tree/master/esm-samples
Following is what I have changed in package.json file:
- "@arcgis/webpack-plugin": "~4.15.0", changed to "@arcgis/core": "^4.19.3";
- "arcgis-js-api": "~4.15.1" is removed;
- "@angular-builders/custom-webpack": "^9.1.0", removd;
- added "webpack": "4.6.0"
Anyone has any suggestions or hints?
Thanks, John
Hi John, we do need to improve our TS doc for this. Here's a working ESM example of a custom layer that is based on this WMS AMD sample:
CustomWMSLayer.ts
import { subclass, property } from "@arcgis/core/core/accessorSupport/decorators";
import BaseDynamicLayer from "@arcgis/core/layers/BaseDynamicLayer";
@subclass("esri.layers.BaseDynamicLayer")
class CustomWMSLayer extends BaseDynamicLayer {
constructor(params?: any) {
super(params);
}
@property()
mapUrl = null;
@property()
mapParameters = null;
getImageUrl(extent, width, height){
const urlVariables = this._prepareQuery(this.mapParameters, extent, width, height);
const queryString = this._joinUrlVariables(urlVariables);
return this.mapUrl + "?" + queryString;
}
// Prepare query parameters for the URL to an image to be generated
private _prepareQuery = (queryParameters, extent, width, height) => {
const wkid = extent.spatialReference.isWebMercator ? 3857 : extent.spatialReference.wkid;
const replacers = {
width: width,
height: height,
wkid: wkid,
xmin: extent.xmin,
xmax: extent.xmax,
ymin: extent.ymin,
ymax: extent.ymax
};
const urlVariables = this._replace({}, queryParameters, replacers);
return urlVariables;
}
// replace the url variables with the application provided values
private _replace = (urlVariables, queryParameters, replacers) => {
Object.keys(queryParameters).forEach((key) => {
urlVariables[key] = Object.keys(replacers).reduce((previous, replacerKey) => {
return previous.replace("{" + replacerKey + "}", replacers[replacerKey]);
}, queryParameters[key]);
});
return urlVariables;
}
// join the url parameters
private _joinUrlVariables = (urlVariables) => {
return Object.keys(urlVariables).reduce((previous, key) => {
return previous + (previous ? "&" : "") + key + "=" + urlVariables[key];
}, "");
}
}
export default CustomWMSLayer;
Here's some psuedo-code showing how to use the custom layer in your component:
import CustomWMSLayer from './CustomWMSLayer';
. . .
// After you initialize the component
const wmsLayer = new CustomWMSLayer({
mapUrl: "https://geobretagne.fr/geoserver/cadastre/ows",
mapParameters: {
SERVICE: "WMS",
REQUEST: "GetMap",
FORMAT: "image/png",
TRANSPARENT: "TRUE",
STYLES: "",
VERSION: "1.3.0",
LAYERS: "CP.CadastralParcel",
WIDTH: "{width}",
HEIGHT: "{height}",
CRS: "EPSG:{wkid}",
BBOX: "{xmin},{ymin},{xmax},{ymax}"
},
minScale: 20000,
title: "Cadastral Parcel"
});
const map = new Map({
basemap: "topo-vector",
layers: [wmsLayer]
});
Hi Andy, Thanks for your reply. This something useful after I have struggled with Esri support for one month. I still have some questions. And at the end of my comments, I will post our simple code there, so you can understand what we are doing.
So base my understanding, what you are saying is Esri do not support function of BaseDynamicLayer.createSubclass(...), instead we need to create a new class of our own, and it extend from BaseDynamicLayer.
My question is :
- Does BaseDynamicLayer class is still supporting a function of fetchImage(extent, width, height), which we need to override?
- The previous fetchImage function returns EsriRequest(...), which now the complier say is not supported, then what is new way to return data? (actually BaseDynamicLayer.createSubclass and EsriRequest is only two things npm run build complains for now on my box). Thank you for your time.
John
Here is our sample code which now get build errors:
this.CustomHighLightLayer = BaseDynamicLayer.createSubclass({
properties: {
serverReturnImageUrl: null, //This makes a call to our local server and gets the image URL (we dont load mapservices/wms through this.)
sessionId: null
},
getValue: function (tag: string, data: any) {
if (data[tag])
return data[tag];
return 0;
},
fetchImage: function (extent, width, height) {
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
canvas.id = "HighLightLayerCanvas";
canvas.width = width;
canvas.height = height;
var self = this;
if (!this.getUrlCallback)
return canvas;
return EsriRequest(self.serverReturnImageUrl(extent, this.sessionId, width, height), { responseType: "json" }).then(
function (results) {
var emptyPromise = new Promise(resolve => resolve({ canvas, status: 'ok' }));
if (!results["data"])
return emptyPromise;
var data = results.data;
if (data) {
var xOffset = self.getValue("offsetX", data);
var yOffset = self.getValue("offsetY", data);
emptyPromise = new Promise(resolve => {
const image = new Image();
image.onload = () => {
context.drawImage(image, xOffset, yOffset);
resolve({ canvas, status: 'ok' });
};
image.onerror = () => resolve({ canvas, status: 'error' });
image.src = data.data;
});
}
return emptyPromise;
}).then(function (result) { return canvas }.bind(this));
}
});
Hi John,
We do support createSubclass() for only JavaScript. I just opened an issue to update the SDK documentation. It's important to note, the implementation patterns are different between JavaScript and TypeScript when extending API classes. The createSubclass() method is the only way to extend the API classes using JavaScript. In comparison, TypeScript code snippet demonstrates combining a @subclass decorator along with an extends keyword to extend BaseDynamicLayer.
For your questions 1 and 2, are you trying to compile createSubclass() in a TypeScript (.ts) file? If so, then you'll need to switch to using the TypeScript pattern similar to what I outlined in my example.
Also just a heads up, with Angular you'll need a minimum of:
- Angular 11.2.5 or greater
- zone.js 0.11.4 or greater
- tsconfig.target to es2017 or greater.
- You may no longer need @arcgis/webpack-plugin, here's some additional information.
Minimum requirements reference: https://github.com/Esri/jsapi-resources/tree/master/esm-samples/jsapi-angular-cli#known-issues
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you need additional assistance please contact Esri Technical Support. Thank you for your contributions.
This issue has been automatically closed due to inactivity. If you need additional assistance please contact Esri Technical Support.