Skip to content

Commit

Permalink
feat: 新增区块-行政区划选择器 (#190)
Browse files Browse the repository at this point in the history
* feat: 缩放器新增显示实时 zoom 数值功能

* docs: 文档showZoom添加默认值

* feat: 区块新增城市联级选择器

* fix: 区块修复城市联级选择器ts报错问题

* docs: 新增区块-行政区划选择器

---------

Co-authored-by: syb01094648 <[email protected]>
Co-authored-by: yanxiong <[email protected]>
  • Loading branch information
3 people authored Sep 27, 2023
1 parent b9d6386 commit 036cc5b
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 0 deletions.
30 changes: 30 additions & 0 deletions docs/blocks/administrative-select.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
toc: false
order: 3
nav:
title: 区块
path: /blocks
order: 4
---

## 城市联级选择器

### 介绍

用于快速查找中国省/市/县行政区域并快速定位的控件,基于 Ant Design 中的 [Cascader](https://ant-design.antgroup.com/components/cascader-cn#api) 组件封装而成

### 代码演示

#### 默认示例

<code src="./administrative-select/demos/default.tsx" compact></code>

### API

| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| autoFit | 是否控制地图自动平移到选项对应行政区域 | `boolean` | `true` |
| enableBoundary | 是否在地图上展示行政区域边界 | `boolean` | `true` |
| boundaryLayer | 边界线图层属性,可参考 [LineLayerProps](https://larkmap.antv.antgroup.com/components/layers/base-layers/line-layer#api) | `Omit<LineLayerProps, 'source'>` | `--` |

其他参数可以参照 [Ant Design 5.0 Cascader](https://ant-design.antgroup.com/components/cascader-cn#api)
156 changes: 156 additions & 0 deletions docs/blocks/administrative-select/administrative-select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import type { LineLayerProps } from '@antv/larkmap';
import { LineLayer, useScene } from '@antv/larkmap';
import type { Feature, MultiLineString } from '@turf/turf';
import { bbox, featureCollection, multiLineString } from '@turf/turf';
import type { CascaderProps } from 'antd';
import { Cascader, message } from 'antd';
import React, { useEffect, useState } from 'react';

export interface AdministrativeSelectProps
extends Omit<CascaderProps, 'options' | 'multiple'>,
Partial<Pick<CascaderProps, 'value' | 'onChange'>> {
/**
* 是否平移
*/
autoFit?: boolean;
/**
* 是否显示边界
*/
enableBoundary?: boolean;
/**
* layer属性
*/
boundaryLayer?: Omit<LineLayerProps, 'source'>;
}

/**
* 将获取的行政区域雷彪转换为 Cascader 的 options
* @param list
* @returns
*/
const getCascadeData = (list: any[]) => {
list.sort((a: { adcode: number }, b: { adcode: number }) => {
return +a.adcode - +b.adcode;
});
if (list.length) {
return list.map((item: any) => {
const { name, districts, adcode } = item;
return {
adcode,
value: adcode,
label: name,
children: getCascadeData(districts),
};
});
} else {
return [];
}
};

export const AdministrativeSelect: React.FC<AdministrativeSelectProps> = ({
enableBoundary,
autoFit,
boundaryLayer,
value: originValue,
onChange,
...props
}) => {
const [districtFeature, setDistrictFeature] = useState<Feature<MultiLineString> | null>(null);
const scene = useScene();
const [options, setOptions] = useState();
const [value, setValue] = useState<AdministrativeSelectProps['value']>(originValue);

useEffect(() => {
setValue(originValue);
}, [originValue]);

useEffect(() => {
fetch(
'https://restapi.amap.com/v3/config/district?key=98d10f05a2da96697313a2ce35ebf1a2&keywords=中华人民共和国&subdistrict=3&extensions=base',
)
.then((res) => res.json())
.then((res) => {
setOptions(getCascadeData(res.districts[0].districts));
});
}, []);

// 当选项发生改变时,更新围栏数据
useEffect(() => {
if (value) {
const name = value[value.length - 1];
fetch(
`https://restapi.amap.com/v3/config/district?keywords=${name}&subdistrict=0&key=98d10f05a2da96697313a2ce35ebf1a2&extensions=all`,
)
.then((res) => res.json())
.then((res) => {
if (res.status === '1' && res.districts?.length && scene) {
const positions: number[][][] = [];
res.districts.forEach((district: any) => {
(district.polyline as string).split('|').forEach((chunk) => {
positions.push(chunk.split(';').map((item) => item.split(',').map((num) => +num)));
});
});

const feature = multiLineString(positions);
setDistrictFeature(feature);
if (autoFit) {
const [lng1, lat1, lng2, lat2] = bbox(feature);
scene.fitBounds([
[lng1, lat1],
[lng2, lat2],
]);
}
}
})
.catch(() => {
message.error('围栏数据请求失败');
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [value]);

return (
<>
<Cascader
options={options}
value={value}
onChange={(newValue: string[], option: any) => {
setValue(newValue);
// @ts-ignore
onChange?.(newValue, option);
if (!value) {
setDistrictFeature(null);
}
}}
multiple={false}
{...props}
/>
{enableBoundary && (
<LineLayer
source={{
data: featureCollection(districtFeature ? [districtFeature] : []),
}}
{...boundaryLayer}
/>
)}
</>
);
};

AdministrativeSelect.defaultProps = {
placeholder: '可选择省/市/县',
expandTrigger: 'hover',
allowClear: true,
changeOnSelect: true,
enableBoundary: true,
autoFit: true,
showSearch: true,
boundaryLayer: {
shape: 'line',
color: '#ff0000',
size: 2,
style: {
opacity: 0.8,
},
},
};
23 changes: 23 additions & 0 deletions docs/blocks/administrative-select/demos/default.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { LarkMapProps } from '@antv/larkmap';
import { CustomControl, LarkMap } from '@antv/larkmap';
import React from 'react';
import { AdministrativeSelect } from '../administrative-select';

const config: LarkMapProps = {
mapType: 'Gaode',
mapOptions: {
style: 'light',
center: [120.210792, 30.246026],
zoom: 9,
},
};

export default () => {
return (
<LarkMap {...config} style={{ height: '300px' }}>
<CustomControl>
<AdministrativeSelect style={{ width: 250 }} />
</CustomControl>
</LarkMap>
);
};

0 comments on commit 036cc5b

Please sign in to comment.