fix(layer): fix sum statistic

This commit is contained in:
thinkinggis 2020-05-27 00:21:09 +08:00
parent 064917c37b
commit 4dc0cfac3c
15 changed files with 264 additions and 79 deletions

View File

@ -0,0 +1,40 @@
import { Scene, HeatmapLayer } from '@antv/l7';
import { Mapbox } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
map: new Mapbox({
style: 'blank',
pitch: 0,
center: [ 110.097892, 33.853662 ],
zoom: 4.056
})
});
scene.on('loaded', () => {
fetch(
'https://gw.alipayobjects.com/os/bmw-prod/3dadb1f5-8f54-4449-8206-72db6e142c40.json'
)
.then(res => res.json())
.then(data => {
const layer = new HeatmapLayer({
autoFit: true
})
.source(data, {
transforms: [
{
type: 'hexagon',
size: 5 * 100000
}
]
})
.shape('circle')
.active(false)
.color('#aaa')
.style({
coverage: 0.7,
angle: 0,
opacity: 1.0
});
scene.addLayer(layer);
});
});

View File

@ -4,6 +4,11 @@
"en": "heatmap" "en": "heatmap"
}, },
"demos": [ "demos": [
{
"filename": "grid_world.js",
"title": "网格世界地图",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*1PeGSboLGUUAAAAAAAAAAABkARQnAQ"
},
{ {
"filename": "china.js", "filename": "china.js",
"title": "网格热力图", "title": "网格热力图",

View File

@ -26,7 +26,7 @@ scene.on('loaded', () => {
transforms: [ transforms: [
{ {
type: 'hexagon', type: 'hexagon',
size: 17000, size: 200000,
field: 'v', field: 'v',
method: 'sum' method: 'sum'
} }

View File

@ -1,6 +1,128 @@
// tslint:disable-next-line:no-submodule-imports // tslint:disable-next-line:no-submodule-imports
import merge from 'lodash/merge'; import merge from 'lodash/merge';
let DataConfig: { [key: string]: any } = {
let DataLevel = 1;
const dataLevel1: { [key: string]: any } = {
world: {
fill: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/d666a08d-fce1-48e2-913a-87d81772bcc9.bin',
},
line: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/62f61f5f-cca7-4137-845d-13c8f9969664.bin',
},
label: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/90c51eb3-04d7-402f-bd05-95e4bd27dd62.bin',
parser: {
type: 'geojson',
},
},
nationalBoundaries: {
type: 'json',
url:
'https://gw.alipayobjects.com/os/bmw-prod/ee493a41-0558-4c0e-bee6-520276c4f1a8.json',
},
},
country: {
CHN: {
1: {
fill: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/25228941-b2ac-4591-b07d-8261ac08d06f.bin',
},
line: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/70ec087e-c48a-4b76-8825-6452f17bae7a.bin',
},
provinceLine: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/0024caaf-86b2-4e75-a3d1-6d2146490b67.bin',
},
label: {
type: 'json',
url:
'https://gw.alipayobjects.com/os/bmw-prod/36832a45-68f8-4b51-b006-9dec71f92a23.json',
},
},
2: {
fill: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/522c6496-c711-4581-88db-c3741cd39abd.bin',
},
line: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/f6a4e2b1-359b-43a6-921c-39d2088d1dab.bin',
},
cityLine: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/f6a4e2b1-359b-43a6-921c-39d2088d1dab.bin',
},
provinceLine: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/0024caaf-86b2-4e75-a3d1-6d2146490b67.bin',
},
},
3: {
fill: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/516b2703-d692-44e6-80dd-b3f5df0186e7.bin',
},
line: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/bc97875a-90f2-42c0-a62c-43d2efd7460d.bin',
},
countryLine: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/bc97875a-90f2-42c0-a62c-43d2efd7460d.bin',
},
cityLine: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/8bfbfe7e-bd0e-4bbe-84d8-629f4dc7abc4.bin',
},
provinceLine: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/778ad7ba-5a3f-4ed6-a94a-b8ab8acae9d6.bin',
},
},
nationalBoundaries: {
type: 'json',
url:
'https://gw.alipayobjects.com/os/bmw-prod/ee493a41-0558-4c0e-bee6-520276c4f1a8.json',
},
nationalBoundaries2: {
type: 'json',
url:
'https://gw.alipayobjects.com/os/bmw-prod/f2189cc4-662b-4358-8573-36f0f918b7ca.json',
},
island: {
type: 'json',
url:
'https://gw.alipayobjects.com/os/bmw-prod/fe49b393-1147-4769-94ed-70471f4ff15d.json',
},
},
},
province: {
110000: '',
},
};
const dataLevel2: { [key: string]: any } = {
world: { world: {
fill: { fill: {
type: 'pbf', type: 'pbf',
@ -121,8 +243,21 @@ let DataConfig: { [key: string]: any } = {
}, },
}; };
function setDataConfig(config: any) { const DataLevelMap: { [key: string]: any } = {
DataConfig = merge(DataConfig, config); 1: dataLevel1,
2: dataLevel2,
};
function setDataConfig(config: any, level: number = DataLevel) {
merge(DataLevelMap[level], config);
}
function getDataConfig(level: number = DataLevel) {
return DataLevelMap[level];
} }
export { setDataConfig, DataConfig }; function setDataLevel(level: number) {
DataLevel = level;
}
const DataConfig = DataLevelMap[DataLevel];
export { setDataConfig, setDataLevel, getDataConfig, DataConfig };

View File

@ -1,4 +1,4 @@
import { DataConfig, setDataConfig } from './config_1'; // import { DataConfig, setDataConfig } from './config_1';
import CityLayer from './layer/city'; import CityLayer from './layer/city';
import CountryLayer from './layer/country'; import CountryLayer from './layer/country';
import CountyLayer from './layer/county'; import CountyLayer from './layer/county';
@ -12,6 +12,5 @@ export {
CityLayer, CityLayer,
CountyLayer, CountyLayer,
DrillDownLayer, DrillDownLayer,
setDataConfig,
DataConfig,
}; };
export * from './config';

View File

@ -17,6 +17,7 @@ import isObject from 'lodash/isObject';
import mergeWith from 'lodash/mergeWith'; import mergeWith from 'lodash/mergeWith';
// @ts-ignore // @ts-ignore
import Pbf from 'pbf'; import Pbf from 'pbf';
import { setDataLevel } from '../config';
import { AttributeType, IDistrictLayerOption } from './interface'; import { AttributeType, IDistrictLayerOption } from './interface';
function mergeCustomizer(objValue: any, srcValue: any) { function mergeCustomizer(objValue: any, srcValue: any) {
@ -39,6 +40,7 @@ export default class BaseLayer extends EventEmitter {
super(); super();
this.scene = scene; this.scene = scene;
this.options = mergeWith(this.getDefaultOption(), option, mergeCustomizer); this.options = mergeWith(this.getDefaultOption(), option, mergeCustomizer);
setDataLevel(this.options.geoDataLevel);
} }
public destroy() { public destroy() {
@ -92,6 +94,7 @@ export default class BaseLayer extends EventEmitter {
protected getDefaultOption(): IDistrictLayerOption { protected getDefaultOption(): IDistrictLayerOption {
return { return {
zIndex: 0, zIndex: 0,
geoDataLevel: 2,
depth: 1, depth: 1,
adcode: [], adcode: [],
joinBy: ['name', 'name'], joinBy: ['name', 'name'],
@ -141,7 +144,7 @@ export default class BaseLayer extends EventEmitter {
chinaNationalWidth: 1, chinaNationalWidth: 1,
popup: { popup: {
enable: true, enable: true,
openTriggerEvent: 'mouseenter', openTriggerEvent: 'mousemove',
closeTriggerEvent: 'mouseout', closeTriggerEvent: 'mouseout',
option: {}, option: {},
Html: (properties: any) => { Html: (properties: any) => {

View File

@ -1,11 +1,3 @@
import {
ILayer,
LineLayer,
PointLayer,
PolygonLayer,
Scene,
StyleAttrField,
} from '@antv/l7';
// tslint:disable-next-line: no-submodule-imports // tslint:disable-next-line: no-submodule-imports
import merge from 'lodash/merge'; import merge from 'lodash/merge';

View File

@ -1,12 +1,5 @@
import { import { LineLayer, PointLayer, Scene, StyleAttrField } from '@antv/l7';
ILayer, import { getDataConfig } from '../index';
LineLayer,
PointLayer,
PolygonLayer,
Scene,
StyleAttrField,
} from '@antv/l7';
import { DataConfig } from '../index';
import BaseLayer from './baseLayer'; import BaseLayer from './baseLayer';
import { IDistrictLayerOption } from './interface'; import { IDistrictLayerOption } from './interface';
@ -16,7 +9,9 @@ export default class CountryLayer extends BaseLayer {
const { depth } = this.options; const { depth } = this.options;
this.addProvinceFill(); this.addProvinceFill();
this.addProvinceLabel(); this.addProvinceLabel();
const countryConfig = DataConfig.country.CHN[depth]; const countryConfig = getDataConfig(this.options.geoDataLevel).country.CHN[
depth
];
this.addProvinceLine(countryConfig.provinceLine); this.addProvinceLine(countryConfig.provinceLine);
@ -29,13 +24,15 @@ export default class CountryLayer extends BaseLayer {
} }
protected async addProvinceFill() { protected async addProvinceFill() {
const { depth } = this.options; const { depth } = this.options;
const countryConfig = DataConfig.country.CHN[depth]; const countryConfig = getDataConfig(this.options.geoDataLevel).CHN[depth];
const fillData = await this.fetchData(countryConfig.fill); const fillData = await this.fetchData(countryConfig.fill);
this.addFillLayer(fillData); this.addFillLayer(fillData);
} }
protected async addProvinceLabel() { protected async addProvinceLabel() {
const { depth } = this.options; const { depth } = this.options;
const countryConfig = DataConfig.country.CHN[depth]; const countryConfig = getDataConfig(this.options.geoDataLevel).country.CHN[
depth
];
const fillLabel = countryConfig.label const fillLabel = countryConfig.label
? await this.fetchData(countryConfig.label) ? await this.fetchData(countryConfig.label)
: null; : null;
@ -93,7 +90,9 @@ export default class CountryLayer extends BaseLayer {
private async loadData() { private async loadData() {
const { depth } = this.options; const { depth } = this.options;
const countryConfig = DataConfig.country.CHN[depth]; const countryConfig = getDataConfig(this.options.geoDataLevel).country.CHN[
depth
];
const fillData = await this.fetchData(countryConfig.fill); const fillData = await this.fetchData(countryConfig.fill);
const fillLabel = countryConfig.label const fillLabel = countryConfig.label
? await this.fetchData(countryConfig.label) ? await this.fetchData(countryConfig.label)

View File

@ -73,6 +73,7 @@ export interface IBubbleOption {
export type adcodeType = string[] | string | number | number[]; export type adcodeType = string[] | string | number | number[];
export interface IDistrictLayerOption { export interface IDistrictLayerOption {
zIndex: number; zIndex: number;
geoDataLevel: 1 | 2;
data?: Array<{ [key: string]: any }>; data?: Array<{ [key: string]: any }>;
joinBy: [string, string]; joinBy: [string, string];
adcode: adcodeType; adcode: adcodeType;

View File

@ -8,7 +8,7 @@ import {
} from '@antv/l7'; } from '@antv/l7';
// tslint:disable-next-line: no-submodule-imports // tslint:disable-next-line: no-submodule-imports
import merge from 'lodash/merge'; import merge from 'lodash/merge';
import { DataConfig } from '../'; import { getDataConfig } from '../';
import BaseLayer from './baseLayer'; import BaseLayer from './baseLayer';
import { adcodeType, IDistrictLayerOption } from './interface'; import { adcodeType, IDistrictLayerOption } from './interface';
@ -97,7 +97,9 @@ export default class ProvinceLayer extends BaseLayer {
} }
private async addProvinceFillLayer() { private async addProvinceFillLayer() {
const { depth, adcode } = this.options as IProvinceLayerOption; const { depth, adcode } = this.options as IProvinceLayerOption;
const countryConfig = DataConfig.country.CHN[depth]; const countryConfig = getDataConfig(this.options.geoDataLevel).country.CHN[
depth
];
const fillData = await this.fetchData(countryConfig.fill); const fillData = await this.fetchData(countryConfig.fill);
this.labelRawData = fillData.features.map((feature: any) => { this.labelRawData = fillData.features.map((feature: any) => {
@ -117,7 +119,9 @@ export default class ProvinceLayer extends BaseLayer {
private async addProvinceLineLayer() { private async addProvinceLineLayer() {
const { depth, adcode } = this.options as IProvinceLayerOption; const { depth, adcode } = this.options as IProvinceLayerOption;
const countryConfig = DataConfig.country.CHN[depth]; const countryConfig = getDataConfig(this.options.geoDataLevel).country.CHN[
depth
];
const fillData = await this.fetchData(countryConfig.line); const fillData = await this.fetchData(countryConfig.line);
const data = this.filterData(fillData, adcode); const data = this.filterData(fillData, adcode);
this.lineRawData = fillData; this.lineRawData = fillData;

View File

@ -6,7 +6,7 @@ import {
Scene, Scene,
StyleAttrField, StyleAttrField,
} from '@antv/l7'; } from '@antv/l7';
import { DataConfig } from '../'; import { getDataConfig } from '../';
import BaseLayer from './baseLayer'; import BaseLayer from './baseLayer';
import { IDistrictLayerOption } from './interface'; import { IDistrictLayerOption } from './interface';
export default class WorldLayer extends BaseLayer { export default class WorldLayer extends BaseLayer {
@ -16,7 +16,7 @@ export default class WorldLayer extends BaseLayer {
this.addFillLayer(fillData); this.addFillLayer(fillData);
this.addFillLine(lineData); this.addFillLine(lineData);
if (this.options.label?.enable) { if (this.options.label?.enable) {
this.addLabelLayer(fillLabel, 'geojson'); this.addLabelLayer(fillLabel, 'json');
} }
}); });
} }
@ -52,11 +52,17 @@ export default class WorldLayer extends BaseLayer {
} }
private async loadData() { private async loadData() {
const countryConfig = DataConfig.world; const countryConfig = getDataConfig(this.options.geoDataLevel).world;
const fillData = await this.fetchData(countryConfig.fill); const fillData = await this.fetchData(countryConfig.fill);
const lineData = await this.fetchData(countryConfig.line); const lineData = await this.fetchData(countryConfig.line);
const fillLabel = await this.fetchData(countryConfig.label); // const fillLabel = await this.fetchData(countryConfig.label);
const fillLabel = fillData.features.map((feature: any) => {
return {
...feature.properties,
center: [feature.properties.x, feature.properties.y],
};
});
return [fillData, lineData, fillLabel]; return [fillData, lineData, fillLabel];
} }
private addNationBorder(boundaries: any, boundaries2: any) { private addNationBorder(boundaries: any, boundaries2: any) {

View File

@ -0,0 +1,10 @@
import { sum } from '../src/statistics';
describe('sum', () => {
it('sum string array', () => {
const a = ['1', '2', '3'];
const b = [1, 2, 3];
// @ts-ignore
expect(sum(a)).toEqual(6);
expect(sum(b)).toEqual(6);
});
});

View File

@ -42,27 +42,12 @@ function sum(x: number[]) {
// Initializing the sum as the first number in the array // Initializing the sum as the first number in the array
let sumNum = x[0] * 1; let sumNum = x[0] * 1;
// Keeping track of the floating-point error correction
let correction = 0;
let transition;
for (let i = 1; i < x.length; i++) { for (let i = 1; i < x.length; i++) {
transition = sumNum + x[i] * 1; sumNum += x[i] * 1;
// Here we need to update the correction in a different fashion
// if the new absolute value is greater than the absolute sum
if (Math.abs(sumNum) >= Math.abs(x[i])) {
correction += sumNum - transition + x[i];
} else {
correction += x[i] - transition + sumNum;
}
sumNum = transition;
} }
// Returning the corrected sum // Returning the corrected sum
return sumNum + correction * 1; return sumNum;
} }
function mean(x: number[]) { function mean(x: number[]) {
if (x.length === 0) { if (x.length === 0) {

View File

@ -44,12 +44,12 @@ export default class Country extends React.Component {
label: { label: {
enable: true, enable: true,
textAllowOverlap: false, textAllowOverlap: false,
field: 'Short_Name_ZH', field: 'NAME_CHN',
}, },
popup: { popup: {
enable: false, enable: false,
Html: (props) => { Html: (props) => {
return `<span>${props.Short_Name_ZH}</span>`; return `<span>${props.NAME_CHN}</span>`;
}, },
}, },
}); });

View File

@ -16,7 +16,7 @@ export default class HexagonLayerDemo extends React.Component {
public async componentDidMount() { public async componentDidMount() {
const scene = new Scene({ const scene = new Scene({
id: 'map', id: 'map',
map: new Mapbox({ map: new GaodeMap({
pitch: 0, pitch: 0,
style: 'blank', style: 'blank',
center: [140.067171, 36.26186], center: [140.067171, 36.26186],
@ -26,40 +26,46 @@ export default class HexagonLayerDemo extends React.Component {
}); });
scene.on('loaded', () => { scene.on('loaded', () => {
fetch( fetch(
'https://gw.alipayobjects.com/os/bmw-prod/3dadb1f5-8f54-4449-8206-72db6e142c40.json', 'https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv',
) )
.then((res) => res.json()) .then((res) => res.text())
.then((data) => { .then((data) => {
const pointLayer = new HeatmapLayer({ const pointLayer = new HeatmapLayer({
autoFit: true, autoFit: true,
}) })
.source(data, { .source(data, {
parser: {
type: 'csv',
x: 'lng',
y: 'lat',
},
transforms: [ transforms: [
{ {
type: 'grid', type: 'hexagon',
size: 500000, size: 200000,
field: 'name', field: 'v',
method: 'mode', method: 'sum',
}, },
], ],
}) })
.shape('square') // 支持 circle, hexagon,triangle .size('sum', (value) => {
.color('mode', [ return value * 20;
'#ffffe5', })
'#fff7bc', .shape('hexagonColumn')
'#fee391', .color(
'#fec44f', 'count',
'#fe9929', [
'#ec7014', '#FF4818',
'#cc4c02', '#F7B74A',
'#993404', '#FFF598',
'#662506', '#FF40F3',
]) '#9415FF',
.active(false) '#421EB2',
].reverse(),
)
.style({ .style({
coverage: 0.7, coverage: 0.9,
// angle: 0.5, angle: 0,
opacity: 1.0,
}); });
scene.addLayer(pointLayer); scene.addLayer(pointLayer);
console.log(pointLayer.getSource()); console.log(pointLayer.getSource());