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"
},
"demos": [
{
"filename": "grid_world.js",
"title": "网格世界地图",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*1PeGSboLGUUAAAAAAAAAAABkARQnAQ"
},
{
"filename": "china.js",
"title": "网格热力图",

View File

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

View File

@ -1,6 +1,128 @@
// tslint:disable-next-line:no-submodule-imports
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: {
fill: {
type: 'pbf',
@ -121,8 +243,21 @@ let DataConfig: { [key: string]: any } = {
},
};
function setDataConfig(config: any) {
DataConfig = merge(DataConfig, config);
const DataLevelMap: { [key: string]: any } = {
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 CountryLayer from './layer/country';
import CountyLayer from './layer/county';
@ -12,6 +12,5 @@ export {
CityLayer,
CountyLayer,
DrillDownLayer,
setDataConfig,
DataConfig,
};
export * from './config';

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ import {
} from '@antv/l7';
// tslint:disable-next-line: no-submodule-imports
import merge from 'lodash/merge';
import { DataConfig } from '../';
import { getDataConfig } from '../';
import BaseLayer from './baseLayer';
import { adcodeType, IDistrictLayerOption } from './interface';
@ -97,7 +97,9 @@ export default class ProvinceLayer extends BaseLayer {
}
private async addProvinceFillLayer() {
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);
this.labelRawData = fillData.features.map((feature: any) => {
@ -117,7 +119,9 @@ export default class ProvinceLayer extends BaseLayer {
private async addProvinceLineLayer() {
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 data = this.filterData(fillData, adcode);
this.lineRawData = fillData;

View File

@ -6,7 +6,7 @@ import {
Scene,
StyleAttrField,
} from '@antv/l7';
import { DataConfig } from '../';
import { getDataConfig } from '../';
import BaseLayer from './baseLayer';
import { IDistrictLayerOption } from './interface';
export default class WorldLayer extends BaseLayer {
@ -16,7 +16,7 @@ export default class WorldLayer extends BaseLayer {
this.addFillLayer(fillData);
this.addFillLine(lineData);
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() {
const countryConfig = DataConfig.world;
const countryConfig = getDataConfig(this.options.geoDataLevel).world;
const fillData = await this.fetchData(countryConfig.fill);
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];
}
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
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++) {
transition = 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;
sumNum += x[i] * 1;
}
// Returning the corrected sum
return sumNum + correction * 1;
return sumNum;
}
function mean(x: number[]) {
if (x.length === 0) {

View File

@ -44,12 +44,12 @@ export default class Country extends React.Component {
label: {
enable: true,
textAllowOverlap: false,
field: 'Short_Name_ZH',
field: 'NAME_CHN',
},
popup: {
enable: false,
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() {
const scene = new Scene({
id: 'map',
map: new Mapbox({
map: new GaodeMap({
pitch: 0,
style: 'blank',
center: [140.067171, 36.26186],
@ -26,40 +26,46 @@ export default class HexagonLayerDemo extends React.Component {
});
scene.on('loaded', () => {
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) => {
const pointLayer = new HeatmapLayer({
autoFit: true,
})
.source(data, {
parser: {
type: 'csv',
x: 'lng',
y: 'lat',
},
transforms: [
{
type: 'grid',
size: 500000,
field: 'name',
method: 'mode',
type: 'hexagon',
size: 200000,
field: 'v',
method: 'sum',
},
],
})
.shape('square') // 支持 circle, hexagon,triangle
.color('mode', [
'#ffffe5',
'#fff7bc',
'#fee391',
'#fec44f',
'#fe9929',
'#ec7014',
'#cc4c02',
'#993404',
'#662506',
])
.active(false)
.size('sum', (value) => {
return value * 20;
})
.shape('hexagonColumn')
.color(
'count',
[
'#FF4818',
'#F7B74A',
'#FFF598',
'#FF40F3',
'#9415FF',
'#421EB2',
].reverse(),
)
.style({
coverage: 0.7,
// angle: 0.5,
opacity: 1.0,
coverage: 0.9,
angle: 0,
});
scene.addLayer(pointLayer);
console.log(pointLayer.getSource());