Back to the proxy approach...

This commit is contained in:
vdv committed 2023-01-20 12:58:56 +01:00
1 parent 0722fca584
commit 982cb722f7
2 files changed
+145 -283

No files matched your search

+95 -131
View File
@@ -1,142 +1,106 @@
import { cloneDeep } from 'lodash';
import { Feature } from 'ol';
import { equals, Extent } from 'ol/extent';
import { fromLonLat, Projection } from 'ol/proj';
import VectorTileSource from 'ol/source/VectorTile.js';
const CLUSTER_PROPS = '[cluster props]';
type FeatureFilter = (
feature: Feature,
resolution: number | undefined
) => boolean;
const passAllFeatureFilter = (feature: Feature, resolution?: number) => true;
interface Props {
extent: Extent | null;
resolution?: number;
extentProjected: Extent | null;
featuresSent: boolean;
featureFilter: FeatureFilter;
}
interface Options {
featureFilter?: FeatureFilter;
source: VectorTileSource;
}
const initialProps = {
extent: null,
extentProjected: null,
featuresSent: false,
featureFilter: passAllFeatureFilter,
};
class ClusterableVectorTileSourceProxy {
extent?: Extent;
resolution?: number;
extentProjected?: Extent;
featuresSent: boolean = false;
proxy?: typeof Proxy;
const getProps = (vectorTileSource: VectorTileSource) =>
vectorTileSource.get(CLUSTER_PROPS) as Props;
const setProps = (vectorTileSource: VectorTileSource, props: Props) =>
vectorTileSource.set(CLUSTER_PROPS, props);
const overloads = {
init: (target: VectorTileSource) => {
return (options?: Options) => {
let props = cloneDeep(initialProps);
if (options) {
props = { ...props, ...options };
}
setProps(target, props);
};
},
loadFeatures: (target: VectorTileSource) => {
return (extent: Extent, resolution: number, projection: Projection) => {
let props = getProps(target);
props.resolution = resolution;
if (props.extent === null || !equals(props.extent, extent)) {
props.extent = extent;
if (target.getProjection() != null) {
props.extentProjected = fromLonLat(
extent.slice(0, 2),
target.getProjection()
).concat(fromLonLat(extent.slice(2), props.projection));
overloads = {
loadFeatures: (target: VectorTileSource) => {
return (extent: Extent, resolution: number, projection: Projection) => {
this.resolution = resolution;
if (this.extent === undefined || !equals(this.extent, extent)) {
this.extent = extent;
if (target.getProjection() != null) {
this.extentProjected = fromLonLat(
extent.slice(0, 2),
target.getProjection()
).concat(fromLonLat(extent.slice(2), this.projection));
}
}
}
if (!props.featuresSent) {
target.dispatchEvent('change');
}
props.featuresSent = false;
setProps(target, props);
// console.log({
// caller: 'clusterableVectorTileSourceProxy',
// overload: 'loadFeatures',
// extent,
// resolution,
// projection,
// target: target,
// props,
// });
};
},
getFeatures: (target: VectorTileSource) => {
return () => {
let props = getProps(target);
const result = (
props.extentProjected !== null
? target.getFeaturesInExtent(props.extentProjected)
: []
).filter((feature) => props.featureFilter(feature, props.resolution));
//console.trace();
props.featuresSent = true;
setProps(target, props);
// console.log({
// caller: 'clusterableVectorTileSourceProxy',
// overload: 'getFeatures',
// result,
// props,
// target,
// });
return result;
};
},
addEventListener: (target: VectorTileSource) => {
return (type: string, listener: any) => {
console.log({
caller: 'clusterableVectorTileSourceProxy',
overload: 'addEventListener',
type,
listener,
target,
});
target.addEventListener(type, listener);
if (type === 'change') {
target.addEventListener('tileloadend', listener);
}
};
},
};
const clusterableVectorTileSourceProxy = (vectorTileSource: VectorTileSource) =>
new Proxy(vectorTileSource, {
get: (target, prop, receiver) => {
let result;
if (prop in overloads) {
result = overloads[prop as keyof typeof overloads](target);
} else {
result = Reflect.get(target, prop, receiver);
}
// console.log({
// caller: 'clusterableVectorTileSourceProxy',
// trap: 'get',
// target,
// prop,
// receiver,
// result,
// });
return result;
if (!this.featuresSent) {
target.dispatchEvent('change');
}
this.featuresSent = false;
// console.log({
// caller: 'clusterableVectorTileSourceProxy',
// overload: 'loadFeatures',
// extent,
// resolution,
// projection,
// target: target,
// this,
// });
};
},
});
export default clusterableVectorTileSourceProxy;
getFeatures: (target: VectorTileSource) => {
return () => {
const result =
this.extentProjected !== undefined
? target.getFeaturesInExtent(this.extentProjected)
: [];
//console.trace();
this.featuresSent = true;
// console.log({
// caller: 'clusterableVectorTileSourceProxy',
// overload: 'getFeatures',
// result,
// this,
// target,
// });
return result;
};
},
addEventListener: (target: VectorTileSource) => {
return (type: string, listener: any) => {
console.log({
caller: 'clusterableVectorTileSourceProxy',
overload: 'addEventListener',
type,
listener,
target,
});
target.addEventListener(type, listener);
if (type === 'change') {
target.addEventListener('tileloadend', listener);
}
};
},
};
constructor(options: Options) {
const { source } = options;
this.proxy = new Proxy(source, {
get: (target, prop, receiver) => {
let result;
if (prop in this.overloads) {
result = this.overloads[prop as keyof typeof this.overloads](target);
} else {
result = Reflect.get(target, prop, receiver);
}
// console.log({
// caller: 'clusterableVectorTileSourceProxy',
// trap: 'get',
// target,
// prop,
// receiver,
// result,
// });
return result;
},
});
return this.proxy;
}
}
export default ClusterableVectorTileSourceProxy;