Fix site map (#846)

* fix: 解决方案页面懒加载

* fix: 添加demo

* 添加两个组件

* fix: 修改样式

* fix: 样式调整

* fix: 更新官网

* fix: 修改样式

Co-authored-by: wb-yzg904416@antgroup.com <wb-yzg904416@antgroup.com>
This commit is contained in:
@thinkinggis 2021-11-21 11:33:43 +08:00 committed by GitHub
parent 97fabe60c7
commit 975fa5777d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 2728 additions and 701 deletions

View File

@ -532,6 +532,18 @@ layer.select(false);
layer.setSelect(id);
```
### getLegendItems
获取图例配置
#### 参数
- name 获取的图例类型 `color|size`
```ts
layer.getLegendItems('color');
```
## 鼠标事件
鼠标事件回调参数 target

View File

@ -39,6 +39,66 @@ module.exports = {
}
}
],
ecosystems: [
{
name: {
zh: 'L7 React组件',
en: 'L7React L7 For React',
},
url: 'http://antv.vision/L7-react/',
},
{
name: {
zh: 'L7 地理围栏绘制组件库',
en: 'L7Draw',
},
url: 'http://antv.vision/L7-draw/',
},
{
name: {
zh: 'L7 行政区划可视化库',
en: 'L7Boundary',
},
url: 'http://antv.vision/L7-boundary/',
},
{
name: {
zh: '地理可视分开发框架',
en: 'Dipper',
},
url: 'http://antv.vision/Dipper',
},
],
Dipper: [
{
name: {
zh: 'L7 React组件',
en: 'L7React L7 For React',
},
url: 'http://antv.vision/L7-react/',
},
{
name: {
zh: 'L7Draw 地理围栏绘制组件库',
en: 'L7Draw',
},
url: 'http://antv.vision/L7-draw/',
},
{
name: {
zh: 'L7Plot',
en: 'L7Plot',
},
url: 'http://antv.vision/L7-draw/',
},
{
name: {
zh: 'L7Boundary 行政区划可视化库',
en: 'L7Boundary',
},
url: 'http://antv.vision/L7-boundary/',
},
],
docs: [
{
slug: 'api/l7',

View File

@ -6,9 +6,10 @@
"url": "https://github.com/antvis/L7"
},
"devDependencies": {
"@antv/dipper": "^0.0.5",
"@antv/dipper-widgets": "^0.0.5",
"@antv/dipper": "0.0.6",
"@antv/dipper-widgets": "0.0.6",
"@antv/g2": "^3.5.9",
"@antv/g2plot": "^2.3.40",
"@antv/gatsby-theme-antv": "^1.1.1",
"@antv/l7-district": "^2.3.9",
"@antv/l7-draw": "^2.3.40",
@ -89,6 +90,7 @@
"jest-styled-components": "^6.2.1",
"lerna": "^3.16.4",
"lint-staged": "^9.2.4",
"mockjs": "^1.1.0",
"npm-run-all": "^4.1.5",
"popmotion": "^9.4.2",
"postcss": "^7.0.18",

View File

@ -0,0 +1,36 @@
// eslint-disable-next-line no-unused-vars
import React from 'react';
import '../../css/dipper.css';
interface DipperProps {
dipper: {
title: string;
image: string;
link: string
}[]
}
export function Dipper(props: DipperProps) {
const { dipper } = props;
const jumoDemo = (url: string) => {
window.open(url, '_blank');
};
return (
<div className='dippercontainer'>
<div className='title'>Dipper </div>
<div className='subtitle'>Dipper L7 </div>
<div className='dipperdemo'>
{dipper.map(item => {
return (
<div key={item.title} className='dipperitem' >
<img className='dipperimg' src={item.image} />
<span style={{cursor:'pointer'}} className='dippertitle'>{item.title}</span>
</div>
);
})}
</div>
</div>
);
}

View File

@ -0,0 +1,43 @@
// eslint-disable-next-line no-unused-vars
import { Carousel } from 'antd';
import React from 'react';
import '../../css/dippermap.css';
interface DipperMapProps {
dippermap: {
desc: string;
img: string;
alt: string
}[]
}
export function DipperMap(props: DipperMapProps) {
const { dippermap } = props;
const jumpDipperMap = (url: string) => {
window.open(url, '_blank');
};
return (
<div className='dippermapcontainer'>
<div className='title'>Dipper Map </div>
<div className='subtitle'>DipperMap L7 </div>
<div className='carousel'>
<Carousel
autoplay
effect='fade'
dotPosition='right'
>
{dippermap.map(item => {
return (
<div>
<h3 style={{ textAlign: 'center' }}>{item.desc}</h3>
<img key={item.alt} alt={item.alt} src={item.img} />
</div>
);
})}
</Carousel>
</div>
</div>
);
}

View File

@ -0,0 +1,43 @@
import React, { useEffect, useRef, useState } from 'react';
import { Bar } from '@antv/g2plot';
export interface ChatData {
data: object[];
legend?: boolean;
loading?: boolean;
}
export function BarCahrt({ data }: ChatData) {
const id = useRef();
const [barplot, setBarplot] = useState<Bar>();
useEffect(() => {
if (!barplot && id.current) {
const bar = new Bar(id.current, {
// @ts-ignore
data: data.sort((a, b) => b.xField - a.xField),
autoFit: true,
xField: 'yField',
yField: 'xField',
xAxis: false,
label: {
position: 'left',
style: {
fill: '#fff',
},
},
legend: {
position: 'top-left',
},
});
bar.render();
setBarplot(bar);
} else {
barplot.update({
data,
});
}
}, [id.current, data]);
return <div ref={id} style={{ height: 300 }} />;
}

View File

@ -0,0 +1,36 @@
import React, { useEffect, useRef, useState } from 'react';
import { Line } from '@antv/g2plot';
import { ChatData } from '../Bar';
import { Spin } from 'antd';
export function LineCahrt({ data, loading }: ChatData) {
const id = useRef();
const [lineplot, setLinePlot] = useState<Line>();
useEffect(() => {
if (!lineplot && id.current && data) {
const lineplot = new Line(id.current, {
data,
autoFit: true,
xField: 'xField',
yField: 'yField',
seriesField: 'series',
legend: {
position: 'top-left',
},
});
lineplot.render();
setLinePlot(lineplot);
} else {
lineplot.update({
data,
});
}
}, [id.current, data]);
return (
<Spin spinning={loading}>
<div ref={id} style={{ height: 300 }} />
</Spin>
);
}

View File

@ -0,0 +1,44 @@
import React, { useEffect, useRef, useState } from 'react';
import { Pie } from '@antv/g2plot';
import { ChatData } from '../Bar';
import { Spin } from 'antd';
export function PieChart({ data, legend, loading }: ChatData) {
const id = useRef();
const [pieplot, setPiePlot] = useState<Pie>();
useEffect(() => {
if (!pieplot && id.current && data) {
const pie = new Pie(id.current, {
data,
autoFit: true,
angleField: 'xField',
colorField: 'yField',
radius: 0.7,
label: {
type: 'spider',
labelHeight: 28,
content: '{name}\n{percentage}',
},
legend: legend
? {
position: 'top-left',
}
: false,
});
pie.render();
setPiePlot(pie);
} else {
pieplot.update({
data,
});
}
}, [id.current, data]);
return (
<Spin spinning={loading}>
<div ref={id} style={{ height: 300 }} />
</Spin>
);
}

View File

@ -0,0 +1,28 @@
import React, { useEffect, useRef, useState } from 'react';
import { Line } from '@antv/g2plot';
import { ChatData } from '../Bar';
export function SingleLineCahrt({ data }: ChatData) {
const id = useRef();
const [lineplot, setLinePlot] = useState<Line>();
useEffect(() => {
if (!lineplot && id.current && data) {
const area = new Line(id.current, {
data,
autoFit: true,
xField: 'xField',
yField: 'yField',
});
area.render();
setLinePlot(area);
}else{
lineplot.update({
data
})
}
}, [id.current,data]);
return <div ref={id} style={{height:300}}/>;
}

View File

@ -0,0 +1,42 @@
import React, { useEffect, useRef, useState } from 'react';
import { Area } from '@antv/g2plot';
import { ChatData } from '../Bar';
export function StackAreaCahrt({ data }: ChatData) {
const id = useRef();
const [pieplot, setAreaPlot] = useState<Area>();
const [list,setData] = useState([])
useEffect(()=>{
fetch('https://gw.alipayobjects.com/os/bmw-prod/b21e7336-0b3e-486c-9070-612ede49284e.json')
.then((res) => res.json())
.then((data) => {
setData(data);
});
},[])
useEffect(() => {
if (!pieplot && id.current && list) {
const area = new Area(id.current, {
data:list,
autoFit: true,
xField: 'date',
yField: 'value',
seriesField: 'country',
legend:{
position:'top-left'
}
});
area.render();
setAreaPlot(area);
}else{
pieplot.update({
data:list
})
}
}, [id.current,data]);
return <div ref={id} style={{height:300}}/>;
}

View File

@ -4,30 +4,20 @@ export const config: Partial<IConfig> = {
viewData: {
global: {
filterData: [],
sceneCode: 'iot_terminal_dominant',
areaCode: '330100',
view: 'task',
},
widgets: {
citySelect: {
options: CityList,
value: [330000, 330100],
value: ['330000', '330100'],
},
},
},
headerbar: {
display: true,
logo: {
display: true,
value:
'https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*ObVJT4IxmlkAAAAAAAAAAAAAARQnAQ',
style: {
height: '24px',
width: '24px',
},
},
title: {
value: '区代指挥中心',
value: '数据分析',
display: true,
},
children: [
@ -41,21 +31,6 @@ export const config: Partial<IConfig> = {
action: 'queryArea',
},
},
{
display: true,
options: [
{
label: '热区分析',
value: 'hotspot',
},
{
label: '任务管理',
value: 'task',
},
],
position: 'center',
type: 'navibar',
},
{
display: false,
position: 'right',
@ -69,24 +44,37 @@ export const config: Partial<IConfig> = {
},
panel: {
display: true,
options: {
enableToggle: true,
defaultTitle: '所有网格',
opened: true,
width: 360,
width: 426,
},
position: 'right',
children: [
{
type: 'siderbartabcontent',
display: true,
type: 'meshName',
title: '网格名称',
},
{
display: true,
type: 'meshchart',
title: '所有网格数据',
},
{
display: false,
type: 'panelTabContent',
title: '所有网格',
children: [
{
display: true,
type: 'mesh_indicator',
title: '数据查看',
title: '业务数据',
},
{
type: 'total_data_panel',
title: '地图面板',
title: '人员数据',
},
],
},
@ -106,9 +94,27 @@ export const config: Partial<IConfig> = {
{
display: true,
position: 'topleft',
type: 'filter',
title: '筛选',
},
{
display: true,
position: 'bottomright',
type: 'location',
title: '定位',
},
{
display: true,
position: 'bottomright',
type: 'mapStyle',
title: '地图样式',
},
{
display: true,
position: 'topleft',
type: 'searchPlaces',
title: '地区搜索',
},
],
defaultcontrols: [
{
@ -136,7 +142,7 @@ export const config: Partial<IConfig> = {
},
fill: {
field: 'unit_price',
color: SingleSequentialColorScale.Blue,
color: ['#A9D3FF', '#82B1FF', '#6294FF', '#457BFF', '#2962FF'],
bandNum: 5,
scale: 'quantile',
unknownName: '无类型',

View File

@ -0,0 +1,267 @@
import Mock from 'mockjs';
// 单折线图
export const singleLineChart = () => {
const data = Mock.mock({
'list|9': [
{
// 生成长度在 100~1000 之间的小写字母
yField: '@integer(0,5000)',
},
],
});
return data.list
.sort((a, b) => a.yField - b.yField)
.map((item, index) => {
return {
xField: `${index + 1}`,
...item,
};
});
};
// 条形图
export const barChart = () => {
let xField = ['餐饮', '影院', '百货购物中心', '国内旅游', '医疗'];
const data = Mock.mock({
'list|5': [
{
// 生成长度在 100~1000 之间的小写字母
yField: '@integer(0,5000)',
},
],
});
return data.list
.sort((a, b) => b.yField - a.yField)
.map((item, index) => {
return {
xField: xField[index],
...item,
};
});
};
// 多维折线图
export const multidimensionalChart = () => {
const series = ['铺设失败', '铺设中', '铺设成功', '虚假铺设'];
const xField = new Array(12).fill('').map((item, index) => {
return `${2 * index + 2}:00`;
});
return series
.map((a, k) => {
return xField.map((b, index) => {
return {
xField: b,
series: a,
yField: Number(
((index + 1) * 10 + 20 * Math.random() + k * 20).toFixed(),
),
};
});
})
.flat();
};
// 作业单数
export const operation = () => {
const data = Mock.mock({
'list|15': [
{
name: '@cname',
order_count: '@integer(0,100)',
staff_no: '@integer(100000,1000000)',
},
],
});
return data.list;
};
// 行业市场份额
export const marketShare = () => {
const data = Mock.mock({
'list|3': [
{
// 生成长度在 100~1000 之间的小写字母
xField: '@integer(0,100)',
},
],
});
const yField = ['街电', '怪兽', '小电'];
return data.list
.sort((a, b) => a.yField - b.yField)
.map((item, index) => {
return {
yField: yField[index],
...item,
};
});
};
// 各品牌营收
export const brandRevenue = () => {
const series = ['街电', '来电', '怪兽', '美团', '小电'];
const xField = new Array(11).fill('').map((item, index) => {
return `${2009 + index}`;
});
return series
.map((a, k) => {
return xField.map((b, index) => {
return {
xField: b,
series: a,
yField: Number(
((index + 1) * 10 + 30 * Math.random() + k * 20).toFixed(),
),
};
});
})
.flat();
};
export function randomData<T>(data: T): Promise<T> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data);
}, 500);
});
}
// 生成范围内的随机数
export const randomNumBoth = (min: number, max: number) => {
const Range = max - min;
const Rand = Math.random();
const num = min + Math.round(Rand * Range);
return num;
}
export const brandOption = [
{ label: '全部类型', value: '1' },
{ label: '街电', value: '2' },
{ label: '怪兽', value: '3' },
{ label: '小电', value: '4' },
];
export const CityList = [
{
value: '330000',
areaLevel: 'province',
label: '浙江省',
children: [
{
value: '330100',
areaLevel: 'city',
label: '杭州市',
children: [],
},
],
},
{
value: '110000',
areaLevel: 'province',
label: '北京市',
children: [
{
value: '110000',
areaLevel: 'city',
label: '北京市',
children: [],
},
],
},
{
value: '120000',
areaLevel: 'province',
label: '天津市',
children: [
{
value: '120000',
areaLevel: 'city',
label: '天津市',
children: [],
},
],
},
{
value: '310000',
areaLevel: 'province',
label: '上海市',
children: [
{
value: '310000',
areaLevel: 'province',
label: '上海市',
children: [],
},
],
},
{
value: '440000',
areaLevel: 'province',
label: '广东省',
children: [
{
value: '440100',
areaLevel: 'city',
label: '广州市',
children: [],
},
{
value: '440300',
areaLevel: 'city',
label: '深圳市',
children: [],
},
{
value: '440400',
areaLevel: 'city',
label: '珠海市',
children: [],
},
{
value: '440600',
areaLevel: 'city',
label: '佛山市',
children: [],
},
{
value: '441300',
areaLevel: 'city',
label: '惠州市',
children: [],
},
{
value: '441900',
areaLevel: 'city',
label: '东莞市',
children: [],
},
{
value: '442000',
areaLevel: 'city',
label: '中山市',
children: [],
},
],
},
{
value: '130000',
areaLevel: 'province',
label: '河北省',
children: [
{
value: '130100',
areaLevel: 'city',
label: '石家庄市',
children: [],
},
{
value: '131000',
areaLevel: 'city',
label: '廊坊市',
children: [],
},
],
},
];

View File

@ -0,0 +1,27 @@
import { initWidgets } from './widgets';
import React, { useEffect, useState } from 'react';
import { config } from './configs/config';
import { DipperContainer, IConfig } from '@antv/dipper';
import 'antd/dist/antd.css'
interface IInitData {
areaVOList: any[];
sceneCode: string;
areaCode: string;
filterData: any[];
}
export default function RumbMap() {
const [mapConfig, setMapConfig] = useState<IConfig<IInitData>>();
// 初始化相关数据
useEffect(() => {
initWidgets();
setMapConfig(config);
}, []);
return (
<div style={{ height: '100%',width:'100%',position:'absolute' }}>
<DipperContainer<IInitData> cfg={mapConfig!} />
</div>
);
}

View File

@ -0,0 +1,42 @@
import { Select } from 'antd';
import React from 'react';
import { useConfigService } from '@antv/dipper';
import { brandOption } from '../configs/mock';
const { Option } = Select;
export const Filter = () => {
const { setWidgetsValue } = useConfigService();
const onBrandChange = (e: any) => {
setWidgetsValue('brand', e);
};
return (
<div style={{ background: '#fff', borderRadius: 3 }}>
<Select
defaultValue="全部地区"
style={{ width: 100, color: 'rgba(0,0,0,0.65)' }}
bordered={false}
>
<Option value="全部地区"></Option>
<Option value="示例地区1">1</Option>
<Option value="示例地区2">2</Option>
</Select>
<Select
defaultValue="1"
style={{ width: 100, color: 'rgba(0,0,0,0.65)' }}
bordered={false}
onChange={(e) => onBrandChange(e)}
>
{brandOption.map((item) => {
return (
<Option key={item.label} value={item.value}>
{item.label}
</Option>
);
})}
</Select>
</div>
);
};

View File

@ -0,0 +1,140 @@
import {
useSceneService,
useConfigService,
LayerGroupEventEnum,
useLayerService,
} from '@antv/dipper';
import React, { useEffect, useMemo, useState } from 'react';
import { GridLayerGroup } from '@antv/dipper';
import { randomNumBoth } from '../configs/mock';
const formatLegend = (data: any[]) => {
return data.map((item) => {
if (Array.isArray(item.value)) {
return {
...item,
value: item.value.map((v) => v.toFixed(2)),
};
} else {
return {
...item,
value: item.value.toFixed(2),
};
}
});
};
export function GridLayer() {
const { layerService } = useLayerService();
const { sceneService } = useSceneService();
const { globalConfig, updateLegend, getWidgetsValue } = useConfigService();
const { layers } = globalConfig;
const [gridLayer, setGridLayer] = useState<GridLayerGroup>();
const cityValue = getWidgetsValue('citySelect');
const brandValue = getWidgetsValue('brand');
const [geoData, setGeoData] = useState();
const layerProps = useMemo(() => {
return layers.find((item: any) => item.type === 'gridLayer');
}, [layers]);
const updateLayerLegend = (items: any[]) => {
updateLegend('gridLayerLegend', {
type: 'classifyColor',
display: true,
position: 'bottomleft',
options: {
title: '充电宝投放数量',
unkownName: layerProps.options.unkownName,
items: items.map((item) => {
return {
color: item.color,
value: item.value.map((v) => {
return (v / 10000).toFixed(2);
}),
};
}),
},
});
};
// 根据筛选器条件请求数据
useEffect(() => {
// 可以根据业务需求配置接口
fetch(
`https://gw.alipayobjects.com/os/antvdemo/assets/dipper-city/${cityValue[1]}.json`,
)
.then((res) => res.json())
.then((data) => {
const geoDataList =
data &&
data.features?.map((item) => {
return {
...item,
properties: {
...item.properties,
brand_type: randomNumBoth(1, 4).toString(), // 充电宝品牌
},
};
});
// 品牌 过滤
if (brandValue && geoDataList) {
// @ts-ignore
const data =
brandValue === '1'
? geoDataList
: geoDataList.filter(
(item) => item.properties.brand_type === brandValue,
);
if (data.length) {
// @ts-ignore
setGeoData({ type: 'FeatureCollection', features: data });
}
} else {
// @ts-ignore
setGeoData({ type: 'FeatureCollection', features: geoDataList });
}
});
// 切换城市 高德地图方法
sceneService.getScene().map?.setCity(cityValue[1]);
}, [JSON.stringify(cityValue), brandValue]);
useEffect(() => {
if (!geoData) {
return;
}
if (gridLayer) {
gridLayer.setData(geoData);
return;
}
const layer = new GridLayerGroup({
name: 'grid',
data: geoData,
options: layerProps.options,
});
layerService.addLayer(layer);
layer.on(LayerGroupEventEnum.DATAUPDATE, () => {
layer.getLegendItem().map((item) => {
if (Array.isArray(item.value)) {
return {
...item,
value: item.value.map((v) => v.toFixed(2)),
};
} else {
return {
...item,
value: item.value.toFixed(2),
};
}
});
updateLayerLegend(formatLegend(layer.getLegendItem()));
});
// 更新图例
updateLayerLegend(formatLegend(layer.getLegendItem()));
setGridLayer(layer);
}, [geoData]);
return <></>;
}

View File

@ -0,0 +1,34 @@
import React, { useEffect, useState } from 'react';
import { useLayerGroup } from '@antv/dipper';
import { brandRevenue, marketShare } from '../../configs/mock';
import { PieChart } from '../../components/Pie';
import { LineCahrt } from '../../components/Line';
export function MeshChart() {
const { selectFeatures } = useLayerGroup('grid');
const [pieData, setPieData] = useState([]);
const [lineData, setLineData] = useState([]);
const [loding, setLoding] = useState(false);
useEffect(() => {
setLoding(true);
setTimeout(() => {
setLoding(false);
setPieData(marketShare());
setLineData(brandRevenue());
}, 300);
}, [JSON.stringify(selectFeatures)]);
return (
<div style={{ padding: '0 15px' }}>
<div>
<h4></h4>
<PieChart data={pieData || []} legend={false} loading={loding} />
</div>
<div>
<h4></h4>
<LineCahrt data={lineData} loading={loding} />
</div>
</div>
);
}

View File

@ -0,0 +1,33 @@
import React, { useState, useEffect } from 'react';
import { useLayerGroup } from '@antv/dipper';
import { SingleLineCahrt } from '../components/SingleLine';
import { singleLineChart, barChart } from '../configs/mock';
import { BarCahrt } from '../components/Bar';
export function MeshIndicator() {
const { selectFeatures } = useLayerGroup('grid');
// lineChart
const [lineData, setLineData] = useState([]);
const [barData, setBarData] = useState([]);
// lineChart
useEffect(() => {
setLineData(singleLineChart());
setBarData(barChart());
}, [JSON.stringify(selectFeatures)]);
return (
<div style={{ overflow: 'auto', height:'630px'}}>
<div>
<div style={{ margin: '10px 0' }}></div>
<SingleLineCahrt data={lineData} />
</div>
<div>
<div style={{ margin: '20px 0' }}></div>
<BarCahrt data={barData} />
</div>
</div>
);
}

View File

@ -0,0 +1,13 @@
.meahname {
padding: 20px;
}
.closeicon {
padding: 0 8px;
}
.edit {
display: flex;
align-items: center;
}
.edit span:hover {
color: #1890ff;
}

View File

@ -0,0 +1,106 @@
import React, {
useRef,
useState,
useMemo,
useCallback,
useEffect,
} from 'react';
import { CheckOutlined, CloseOutlined, EditOutlined } from '@ant-design/icons';
import styles from './index.module.css'
import { Input } from 'antd';
import { useLayerGroup, useConfigService } from '@antv/dipper';
import _ from 'loadsh';
export function MeshName() {
const { selectFeatures, updateProperties } = useLayerGroup('grid');
const [edit, setEdit] = useState(false);
const ref = useRef();
const { setConfig } = useConfigService();
/**
* get meshname
* type []string
*/
const meshName = useMemo(() => {
if (!selectFeatures.length) return [];
return selectFeatures.map((item) => {
// @ts-ignore
return item.feature.properties.name;
});
}, [JSON.stringify(selectFeatures)]);
// 修改 网格名称
const editMeshName = useCallback(() => {
// @ts-ignore
const value = ref.current.state.value;
selectFeatures.forEach((item) => {
const properties = {
...item.feature.properties,
name: value,
};
updateProperties(item.feature, properties);
});
setEdit(false);
}, [JSON.stringify(selectFeatures)]);
// select more meshname 编辑 网格名称
const EditMeshName = () => {
return (
<>
{!edit ? (
<div onClick={() => setEdit(!edit)}>
<span>{meshName}</span>
<EditOutlined style={{ paddingLeft: 12 }} />
</div>
) : (
<div className={styles.edit}>
<Input defaultValue={meshName} ref={ref} />
<CheckOutlined
onClick={editMeshName}
className={styles.closeicon}
/>
<CloseOutlined onClick={() => setEdit(false)} />
</div>
)}
</>
);
};
// show 多个网格名称
const ShowMeshNames = () => {
return (
<div style={{ padding: 15 }}>
{meshName.length >= 2 &&
meshName.map((s) => {
return <span key={s}>
{s}
</span>;
})}
</div>
);
};
useEffect(() => {
if (selectFeatures.length) {
// TODO 报错
setConfig(`panel.children.1.display`, false);
setConfig(`panel.children.2.display`, true);
// setConfig(`panel.children.${findIdMeshchart}.display`, false)
} else {
setConfig(`panel.children.1.display`, true);
setConfig(`panel.children.2.display`, false);
}
}, [JSON.stringify(selectFeatures)]);
return (
<>
{meshName && meshName.length ? (
<div className={styles.meahname}>
{meshName.length === 1 ? <EditMeshName /> : <ShowMeshNames />}
</div>
) : (
<h4 style={{ padding: 15 }}></h4>
)}
</>
);
}

View File

@ -0,0 +1,37 @@
.teamcontainer {
margin: 10px 0;
display: flex;
align-items: center;
justify-content: space-between;
}
.orderlist {
display: flex;
align-items: center;
justify-content: space-between;
height: 48px;
width: 378px;
background: #fafafa;
border-radius: 2px;
padding: 0 5px;
}
.orderlist .leftpart {
display: flex;
align-items: center;
}
.orderlist .leftpart > div {
padding-right: 15px;
}
.orderlist .leftpart .ordericon {
width: 16px;
height: 16px;
margin-right: 10px;
}
.sort:hover {
color: #1e73f8;
}
.orderCon :global .ant-list-split .ant-list-item {
border: none !important;
}
.orderCon :global .ant-list-item {
padding: 5px 0 !important;
}

View File

@ -0,0 +1,116 @@
import React, { useState, useEffect } from 'react';
import { useLayerGroup } from '@antv/dipper'
import { Button, List } from 'antd';
import { multidimensionalChart, operation } from '../../configs/mock';
import styles from './index.module.css'
import { LineCahrt } from '../../components/Line';
enum Sort {
Up,
Dowm,
}
const No1 =
'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*grCBQ4izMjcAAAAAAAAAAAAAARQnAQ';
const No2 =
'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*r0DyQIluJ8QAAAAAAAAAAAAAARQnAQ';
const No3 =
'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*5R92QrzHW7YAAAAAAAAAAAAAARQnAQ';
export function TotalPanel() {
const { selectFeatures = [] } = useLayerGroup('grid');
const [lineData, setLineData] = useState([]);
const [orderData, setOrderData] = useState([]);
const [ordersort, setOrderSort] = useState<Sort>(1);
const [loading, setLoading] = useState(false);
// lineChart
useEffect(() => {
setLoading(true)
setTimeout(()=>{
setLoading(false)
setLineData(multidimensionalChart());
},300)
}, [JSON.stringify(selectFeatures)]);
useEffect(() => {
if (ordersort === undefined) {
return setOrderData(operation());
}
const sortData = operation();
if (ordersort === 0) {
return setOrderData(
sortData.sort((a, b) => a.order_count - b.order_count),
);
}
if (ordersort === 1) {
return setOrderData(
sortData.sort((a, b) => b.order_count - a.order_count),
);
}
}, [selectFeatures, ordersort]);
// 排序
const sorts = (type: Sort) => {
setOrderSort(type);
};
// orderData index 与 icon 映射
const iconOrder = { 1: No1, 2: No2, 3: No3 };
return (
<div style={{ overflow: 'auto', height:'560px'}}>
<div>
<h4></h4>
<LineCahrt data={lineData} loading={loading}/>
</div>
<div className={styles.orderCon}>
<div className={styles.teamcontainer}>
<div></div>
<div>
<Button
type={ordersort === 1 ? 'link' : 'text'}
className={styles.sort}
onClick={() => sorts(1)}
>
</Button>
<Button
type={ordersort === 0 ? 'link' : 'text'}
className={styles.sort}
onClick={() => sorts(0)}
>
</Button>
</div>
</div>
{orderData && (
<List
dataSource={orderData}
renderItem={(item, index) => (
<List.Item>
<div className={styles.orderlist}>
<div className={styles.leftpart}>
{index <= 2 ? (
<img
src={iconOrder[index + 1]}
className={styles.ordericon}
/>
) : (
<div>{index + 1}</div>
)}
<span>
{item.name}({item.staff_no})
</span>
</div>
<div>{item.order_count}</div>
</div>
</List.Item>
)}
/>
)}
</div>
</div>
);
}

View File

@ -0,0 +1,34 @@
import { registerWidget } from '@antv/dipper-core';
import {
CitySelect,
NavBar,
ClassifyColor,
DiscreteColor,
Draw,
MapStyle,
SearchPlace,
Location,
} from '@antv/dipper-widgets';
import { GridLayer } from './GridLayer';
import { MeshIndicator } from './MeshIndicator';
import { MeshName } from './MeshName';
import { Filter } from './Filter';
import { TotalPanel } from './TotalPanel/index';
import { MeshChart } from './MeshChart';
export function initWidgets() {
registerWidget('citySelect', CitySelect);
registerWidget('navibar', NavBar);
registerWidget('gridLayer', GridLayer);
registerWidget('classifyColor', ClassifyColor);
registerWidget('discreteColor', DiscreteColor);
registerWidget('mapStyle', MapStyle);
registerWidget('searchPlaces', SearchPlace);
registerWidget('location', Location);
registerWidget('filter', Filter);
registerWidget('mesh_indicator', MeshIndicator);
registerWidget('total_data_panel', TotalPanel);
registerWidget('meshchart', MeshChart);
registerWidget('draw', Draw);
registerWidget('meshName',MeshName)
}

View File

@ -1,532 +0,0 @@
export const geojson = [
{
type: 'Feature',
properties: {
label: 'A类区域',
value: 'A',
featureId: '2021102300040027',
id: '2021102300040027',
name: '哈哈6666',
groupId: '2021102300073562',
canvasId: '2021102300077947',
creator: '285869',
modifier: 'WB904416',
gmtCreate: '2021-10-23T13:23:53.000+00:00',
gmtModified: '2021-10-29T08:43:06.000+00:00',
status: 1,
bizId: 'ALGO13301000000030038b',
source: 'INIT',
extInfo: {
area_centroid: '[120.200270,30.137812]',
},
},
geometry: {
type: 'Polygon',
coordinates: [
[
[120.147844, 30.143857],
[120.146688, 30.144529],
[120.145292, 30.145769],
[120.14333, 30.146841],
[120.138229, 30.153274],
[120.133322, 30.160392],
[120.132625, 30.161615],
[120.135188, 30.16281],
[120.136067, 30.163429],
[120.137014, 30.164436],
[120.138875, 30.167409],
[120.139576, 30.168271],
[120.140893, 30.169368],
[120.141752, 30.169944],
[120.144082, 30.170827],
[120.147209, 30.171816],
[120.151231, 30.172756],
[120.154113, 30.173337],
[120.155476, 30.173477],
[120.158666, 30.173408],
[120.158813, 30.173182],
[120.167716, 30.173249],
[120.167809, 30.173079],
[120.167644, 30.172555],
[120.167663, 30.172204],
[120.168217, 30.171148],
[120.168583, 30.170715],
[120.168799, 30.169991],
[120.16937, 30.169203],
[120.168394, 30.168113],
[120.167832, 30.167112],
[120.170001, 30.162286],
[120.170393, 30.161163],
[120.170857, 30.160363],
[120.171268, 30.159909],
[120.171843, 30.159472],
[120.172585, 30.159084],
[120.173472, 30.158806],
[120.176516, 30.158457],
[120.178244, 30.158018],
[120.181234, 30.156641],
[120.182546, 30.156143],
[120.187335, 30.155265],
[120.188246, 30.155308],
[120.188949, 30.155505],
[120.189517, 30.155768],
[120.190041, 30.156122],
[120.191852, 30.157747],
[120.192457, 30.158198],
[120.199627, 30.161976],
[120.200393, 30.161113],
[120.201372, 30.160261],
[120.204072, 30.158385],
[120.204474, 30.157992],
[120.205018, 30.15764],
[120.205398, 30.157546],
[120.205887, 30.157658],
[120.205706, 30.15851],
[120.206192, 30.158863],
[120.206058, 30.159513],
[120.206121, 30.159901],
[120.207273, 30.160486],
[120.208006, 30.160419],
[120.208488, 30.159493],
[120.208835, 30.158228],
[120.208544, 30.157534],
[120.206494, 30.157128],
[120.207878, 30.156136],
[120.208276, 30.156082],
[120.208298, 30.156518],
[120.209071, 30.157141],
[120.210222, 30.156577],
[120.210388, 30.157044],
[120.210978, 30.157462],
[120.212571, 30.158131],
[120.212937, 30.158078],
[120.213941, 30.157481],
[120.214887, 30.159206],
[120.214888, 30.160837],
[120.215479, 30.161676],
[120.215645, 30.162161],
[120.215948, 30.162305],
[120.218933, 30.162964],
[120.21947, 30.162984],
[120.221036, 30.16208],
[120.221542, 30.161941],
[120.221799, 30.162783],
[120.222203, 30.163521],
[120.222931, 30.164169],
[120.225012, 30.165453],
[120.225443, 30.165901],
[120.226118, 30.16827],
[120.226124, 30.168557],
[120.225875, 30.168755],
[120.226207, 30.170185],
[120.226446, 30.170469],
[120.226639, 30.170573],
[120.227512, 30.170626],
[120.227522, 30.171242],
[120.227796, 30.171909],
[120.229737, 30.172137],
[120.229916, 30.171461],
[120.23, 30.170618],
[120.230569, 30.170018],
[120.233933, 30.169673],
[120.23455, 30.165985],
[120.234458, 30.164828],
[120.234558, 30.162136],
[120.234676, 30.16115],
[120.235118, 30.159612],
[120.235576, 30.158653],
[120.235617, 30.15825],
[120.236053, 30.157277],
[120.235382, 30.157034],
[120.235301, 30.156572],
[120.23496, 30.156239],
[120.234249, 30.155793],
[120.233696, 30.155684],
[120.2332, 30.15573],
[120.232496, 30.155586],
[120.23286, 30.154907],
[120.233495, 30.154176],
[120.232856, 30.153878],
[120.232683, 30.153433],
[120.232879, 30.153278],
[120.232872, 30.152843],
[120.232724, 30.152397],
[120.23234, 30.151877],
[120.231848, 30.151555],
[120.231595, 30.151273],
[120.231185, 30.150624],
[120.230557, 30.150187],
[120.230053, 30.149345],
[120.229281, 30.148778],
[120.228917, 30.148747],
[120.228421, 30.14842],
[120.228184, 30.147479],
[120.226923, 30.147425],
[120.226418, 30.147328],
[120.225486, 30.147388],
[120.226496, 30.146217],
[120.225966, 30.145733],
[120.225583, 30.145521],
[120.225428, 30.14502],
[120.224312, 30.14501],
[120.223858, 30.144788],
[120.223652, 30.144476],
[120.223478, 30.144345],
[120.222825, 30.14418],
[120.222569, 30.14428],
[120.221885, 30.144124],
[120.221396, 30.144273],
[120.220971, 30.1447],
[120.220603, 30.144724],
[120.220295, 30.144623],
[120.220024, 30.144701],
[120.219842, 30.144619],
[120.219654, 30.144693],
[120.219384, 30.144654],
[120.218498, 30.144158],
[120.217793, 30.143521],
[120.217119, 30.143362],
[120.216758, 30.14301],
[120.216674, 30.14272],
[120.216732, 30.142301],
[120.217668, 30.141623],
[120.218151, 30.141431],
[120.220282, 30.139534],
[120.220356, 30.140206],
[120.220619, 30.140315],
[120.220731, 30.140486],
[120.221293, 30.140608],
[120.221736, 30.140936],
[120.221342, 30.141563],
[120.22151, 30.141869],
[120.220996, 30.142466],
[120.22197, 30.142837],
[120.223564, 30.142785],
[120.223847, 30.142422],
[120.223877, 30.142059],
[120.223806, 30.141797],
[120.221855, 30.139726],
[120.2231, 30.140085],
[120.223641, 30.140564],
[120.223948, 30.141129],
[120.223997, 30.141173],
[120.224257, 30.141696],
[120.224258, 30.142105],
[120.224381, 30.142548],
[120.224535, 30.142716],
[120.224726, 30.143188],
[120.2255, 30.143728],
[120.226119, 30.144357],
[120.226434, 30.14455],
[120.228071, 30.144609],
[120.229719, 30.144786],
[120.229908, 30.14485],
[120.23018, 30.145286],
[120.230407, 30.145484],
[120.231237, 30.145853],
[120.231382, 30.146076],
[120.231631, 30.146207],
[120.232288, 30.146322],
[120.233052, 30.146667],
[120.23368, 30.14734],
[120.233786, 30.147891],
[120.234623, 30.14832],
[120.234839, 30.148646],
[120.235314, 30.149087],
[120.23548, 30.149626],
[120.235721, 30.149938],
[120.236457, 30.150391],
[120.23716, 30.150539],
[120.237485, 30.150801],
[120.23803, 30.151477],
[120.239139, 30.152535],
[120.23946, 30.153088],
[120.240229, 30.153121],
[120.240626, 30.152351],
[120.241359, 30.151459],
[120.242314, 30.150725],
[120.245302, 30.148847],
[120.24628, 30.147889],
[120.247034, 30.146693],
[120.247423, 30.145397],
[120.247992, 30.145405],
[120.248012, 30.143993],
[120.247725, 30.142724],
[120.247166, 30.142646],
[120.242305, 30.130879],
[120.241721, 30.130596],
[120.240334, 30.12946],
[120.239997, 30.129042],
[120.238317, 30.125574],
[120.237006, 30.123431],
[120.236783, 30.122886],
[120.235868, 30.122206],
[120.236571, 30.122049],
[120.23665, 30.121468],
[120.235894, 30.119696],
[120.235675, 30.118672],
[120.235701, 30.117587],
[120.235629, 30.11654],
[120.235379, 30.116023],
[120.233483, 30.116034],
[120.233123, 30.116188],
[120.232895, 30.116075],
[120.231727, 30.115965],
[120.230487, 30.116072],
[120.230015, 30.116313],
[120.229969, 30.115245],
[120.229787, 30.11438],
[120.229945, 30.113327],
[120.232144, 30.112345],
[120.233516, 30.111985],
[120.235989, 30.111814],
[120.234895, 30.107582],
[120.234778, 30.106555],
[120.234895, 30.104915],
[120.230596, 30.103151],
[120.2278, 30.101876],
[120.226383, 30.101599],
[120.222325, 30.1023],
[120.2147, 30.103149],
[120.212667, 30.103445],
[120.21219, 30.10365],
[120.211945, 30.103932],
[120.210495, 30.107288],
[120.209991, 30.108123],
[120.209384, 30.108529],
[120.208824, 30.10864],
[120.208085, 30.108556],
[120.205857, 30.107717],
[120.205393, 30.107652],
[120.204861, 30.107693],
[120.201864, 30.109287],
[120.20089, 30.109712],
[120.199973, 30.109881],
[120.193121, 30.109323],
[120.191151, 30.109647],
[120.190646, 30.109835],
[120.190888, 30.111217],
[120.190796, 30.111259],
[120.190086, 30.109884],
[120.189525, 30.109667],
[120.18587, 30.107744],
[120.185064, 30.109015],
[120.183326, 30.113489],
[120.18151, 30.11587],
[120.180172, 30.11726],
[120.177758, 30.119219],
[120.174527, 30.121509],
[120.173028, 30.122505],
[120.172232, 30.122899],
[120.171456, 30.123117],
[120.170975, 30.12361],
[120.170378, 30.12466],
[120.166094, 30.128398],
[120.165454, 30.129692],
[120.164526, 30.130852],
[120.163489, 30.131706],
[120.162161, 30.132556],
[120.160762, 30.133219],
[120.158745, 30.134854],
[120.156354, 30.137038],
[120.154387, 30.138586],
[120.152292, 30.139893],
[120.150055, 30.14083],
[120.149208, 30.142005],
[120.148552, 30.143085],
[120.147844, 30.143857],
],
],
},
},
{
type: 'Feature',
properties: {
label: 'B类区域',
value: 'B',
featureId: '2021102300040027',
id: '2021102300040027',
name: '于争光',
groupId: '2021102300073562',
canvasId: '2021102300077947',
creator: '285869',
modifier: 'WB904416',
gmtCreate: '2021-10-23T13:23:53.000+00:00',
gmtModified: '2021-10-29T08:43:06.000+00:00',
status: 1,
bizId: 'ALGO13301000000030038b',
source: 'INIT',
extInfo: {
area_centroid: '[120.200270,30.137812]',
},
},
geometry: {
type: 'Polygon',
coordinates: [
[
[120.1636505126953, 30.24631485403797],
[120.17704010009766, 30.22970466206658],
[120.19214630126953, 30.243942141326617],
[120.1636505126953, 30.24631485403797],
],
],
},
},
{
type: 'Feature',
properties: {
label: 'C类区域',
value: 'C',
featureId: '2021102300040027',
id: '2021102300040027',
name: 'ecnevnevnec',
groupId: '2021102300073562',
canvasId: '2021102300077947',
creator: '285869',
modifier: 'WB904416',
gmtCreate: '2021-10-23T13:23:53.000+00:00',
gmtModified: '2021-10-29T08:43:06.000+00:00',
status: 1,
bizId: 'ALGO13301000000030038b',
source: 'INIT',
extInfo: {
area_centroid: '[120.200270,30.137812]',
},
},
geometry: {
type: 'Polygon',
coordinates: [
[
[120.09017944335938, 30.224958377428475],
[120.08949279785156, 30.18994745521063],
[120.14751434326172, 30.189353942421295],
[120.14854431152342, 30.22466172703242],
[120.09017944335938, 30.224958377428475],
],
],
},
},
];
export const CityList = [
{
value: '330000',
areaLevel: 'province',
label: '浙江省',
children: [
{
value: '330100',
areaLevel: 'city',
label: '杭州市',
children: [],
},
],
},
{
value: '110000',
areaLevel: 'province',
label: '北京市',
children: [
{
value: '110000',
areaLevel: 'city',
label: '北京市',
children: [],
},
],
},
{
value: '120000',
areaLevel: 'province',
label: '天津市',
children: [
{
value: '120000',
areaLevel: 'city',
label: '天津市',
children: [],
},
],
},
{
value: '310000',
areaLevel: 'province',
label: '上海市',
children: [
{
value: '310000',
areaLevel: 'province',
label: '上海市',
children: [],
},
],
},
{
value: '440000',
areaLevel: 'province',
label: '广东省',
children: [
{
value: '440100',
areaLevel: 'city',
label: '广州市',
children: [],
},
{
value: '440300',
areaLevel: 'city',
label: '深圳市',
children: [],
},
{
value: '440400',
areaLevel: 'city',
label: '珠海市',
children: [],
},
{
value: '440600',
areaLevel: 'city',
label: '佛山市',
children: [],
},
{
value: '441300',
areaLevel: 'city',
label: '惠州市',
children: [],
},
{
value: '441900',
areaLevel: 'city',
label: '东莞市',
children: [],
},
{
value: '442000',
areaLevel: 'city',
label: '中山市',
children: [],
},
],
},
{
value: '130000',
areaLevel: 'province',
label: '河北省',
children: [
{
value: '130100',
areaLevel: 'city',
label: '石家庄市',
children: [],
},
{
value: '131000',
areaLevel: 'city',
label: '廊坊市',
children: [],
},
],
},
];

View File

@ -1,20 +0,0 @@
import { registerWidget } from '@antv/dipper-core';
import {
CitySelect,
SiderBar,
NavBar,
ClassifyColor,
DiscreteColor,
} from '@antv/dipper-widgets';
import { GridLayer } from './GridLayer';
import { MapStyle } from '@antv/dipper-widgets';
export function initWidgets() {
registerWidget('citySelect', CitySelect);
registerWidget('siderbartabcontent', SiderBar);
registerWidget('navibar', NavBar);
registerWidget('gridLayer', GridLayer);
registerWidget('classifyColor', ClassifyColor);
registerWidget('discreteColor', DiscreteColor);
registerWidget('mapStyle', MapStyle);
}

View File

@ -0,0 +1,37 @@
import React, { useEffect, useRef, useState } from 'react';
import { Bar } from '@antv/g2plot';
export interface ChatData {
data: object[];
}
export function BarChart({ data }: ChatData) {
const id = useRef();
const [barplot, setBarplot] = useState<Bar>();
useEffect(() => {
if (!barplot && id.current) {
const bar = new Bar(id.current, {
// @ts-ignore
data: data.sort((a, b) => b.xField - a.xField),
autoFit: true,
xField: 'xField',
yField: 'yField',
xAxis: false,
label: {
position: 'left',
style: {
fill: '#fff',
},
},
legend: {
position: 'top-left',
},
});
bar.render();
setBarplot(bar);
}
}, []);
return <div ref={id} style={{ height: 300 }} />;
}

View File

@ -0,0 +1,42 @@
import React, { useEffect, useRef, useState } from 'react';
import { Line } from '@antv/g2plot';
import { ChatData } from '../Bar';
export function LineChart({ data }: ChatData) {
const id = useRef();
const [lineplot, setLinePlot] = useState<Line>();
const [list, setData] = useState([]);
useEffect(() => {
fetch(
'https://gw.alipayobjects.com/os/bmw-prod/b21e7336-0b3e-486c-9070-612ede49284e.json',
)
.then((res) => res.json())
.then((data) => {
setData(data);
});
}, []);
useEffect(() => {
if (!lineplot && id.current && list) {
const area = new Line(id.current, {
data: list,
autoFit: true,
xField: 'date',
yField: 'value',
seriesField: 'country',
legend: {
position: 'top-left',
},
});
area.render();
setLinePlot(area);
} else {
lineplot.update({
data: list,
});
}
}, [id.current, list]);
return <div ref={id} style={{ height: 300 }} />;
}

View File

@ -0,0 +1,33 @@
import React, { useEffect, useRef, useState } from 'react';
import { Pie } from '@antv/g2plot';
import { ChatData } from '../Bar';
export function PieChart({ data }: ChatData) {
const id = useRef();
const [pieplot, setPiePlot] = useState<Pie>();
useEffect(() => {
if (!pieplot && id.current && data) {
const bar = new Pie(id.current, {
data,
autoFit: true,
angleField: 'xField',
colorField: 'yField',
radius: 0.7,
label: {
type: 'spider',
labelHeight: 28,
content: '{name}\n{percentage}',
},
legend: {
position: 'top-left',
},
});
bar.render();
setPiePlot(bar);
}
}, [id.current, data]);
return <div ref={id} style={{ height: 300 }} />;
}

View File

@ -0,0 +1,42 @@
import React, { useEffect, useRef, useState } from 'react';
import { Area } from '@antv/g2plot';
import { ChatData } from '../Bar';
export function StackAreaChart({ data }: ChatData) {
const id = useRef();
const [pieplot, setAreaPlot] = useState<Area>();
const [list, setData] = useState([]);
useEffect(() => {
fetch(
'https://gw.alipayobjects.com/os/bmw-prod/b21e7336-0b3e-486c-9070-612ede49284e.json',
)
.then((res) => res.json())
.then((data) => {
setData(data);
});
}, []);
useEffect(() => {
if (!pieplot && id.current && list) {
const area = new Area(id.current, {
data: list,
autoFit: true,
xField: 'date',
yField: 'value',
seriesField: 'country',
legend: {
position: 'top-left',
},
});
area.render();
setAreaPlot(area);
} else {
pieplot.update({
data: list,
});
}
}, [id.current, data]);
return <div ref={id} style={{ height: 300 }} />;
}

View File

@ -0,0 +1,168 @@
import { IConfig, SingleSequentialColorScale } from '@antv/dipper';
import { CityList } from './mock';
export const config: Partial<IConfig> = {
viewData: {
global: {
filterData: [],
areaCode: '110000',
view: 'task',
},
widgets: {
citySelect: {
options: CityList,
value: ['110000', '110000'],
},
},
},
headerbar: {
display: true,
title: {
value: 'XX 管理地图地图',
display: true,
},
children: [
{
display: true,
position: 'left',
title: '选择城市',
type: 'citySelect',
event: {
actionType: 'map',
action: 'queryArea',
},
},
],
},
panel: {
display: true,
position: 'right',
options: {
enableToggle: true,
defaultTitle: '所有网格',
opened: true,
width: 426,
},
children: [
{
display: true,
type: 'meshName',
title: '网格名称',
},
{
display: true,
type: 'activityTask',
title: '活动任务',
},
],
},
toolbar: {
display: true,
children: [
{
display: true,
position: 'left',
title: '全部活动',
type: 'activity',
},
{
display: true,
position: 'left',
title: '全部状态',
type: 'status',
},
{
display: true,
position: 'left',
title: '地图展示',
type: 'mapExhibit',
},
{
display: true,
position: 'left',
title: '人员搜索',
type: 'searchPerson',
},
{
display: true,
position: 'right',
title: '保存',
type: 'save',
},
{
display: true,
position: 'right',
type: 'publishbar',
title: '发布',
event: {
actionType: 'map',
action: 'publish',
},
},
],
},
map: {
zoom: 10,
center: [120.153576, 30.287459],
pitch: 0,
style: 'normal',
},
controls: [
{
display: true,
position: 'bottomright',
type: 'mapStyle',
title: '地图样式',
},
{
display: true,
position: 'rightcenter',
type: 'meshTools',
title: '网格工具',
},
{
display: true,
position: 'bottomright',
type: 'location',
title: '定位',
},
],
defaultcontrols: [
{
type: 'zoom',
position: 'bottomright',
display: true,
},
{
type: 'scale',
position: 'bottomleft',
display: true,
},
],
popup: {
enable: false,
},
layers: [
{
type: 'gridLayer',
options: {
label: {
field: 'name',
size: 12,
color: '#000',
},
fill: {
field: 'unit_price',
color: ['#CFE1B9', '#B0C298', '#90A276', '#718355'],
unknownName: '无类型',
scale: {
type: 'cat',
domain: ['C', 'B', 'A'],
},
},
},
},
],
legends: [],
};

View File

@ -0,0 +1,199 @@
import Mock from 'mockjs';
export const chartList = Mock.mock({
// 生成长度在 0~32 之间的小写字母
success: '@string("lower", 0, 32)',
// 生成长度在 0~32 之间的小写字母
errorMessage: '@string("lower", 0, 32)',
data: {
'list|4-7': [
{
// 生成长度在 100~1000 之间的小写字母
xField: '@integer(100,1000)',
// 生成长度在 3~5 之间的中文
yField: '@ctitle(3, 5)',
},
],
},
});
export const personOption = () => {
const data = Mock.mock({
'list|10': [
{
label: '@cname',
staffNo: '@integer(100000,1000000)',
value: '@integer(100000,1000000)'
},
],
})
return data.list
}
export const selectActivityItem = [
{
label: '双十一赢金币',
value: '双十一赢金币',
icon: 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*JYNuSaNAga8AAAAAAAAAAAAAARQnAQ'
},
{
label: '充电桩铺设',
value: '充电桩铺设',
icon: 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*eay2Q7nXeG4AAAAAAAAAAAAAARQnAQ'
},
{
label: '1块钱升级月卡',
value: '1块钱升级月卡',
icon: 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*nA0vQbl_hGMAAAAAAAAAAAAAARQnAQ'
},
{
label: '免费充电1小时',
value: '免费充电1小时',
icon: 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*snkKRYonMgEAAAAAAAAAAAAAARQnAQ'
},
]
export function randomData<T>(data: T): Promise<T> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data);
}, 500);
});
}
export const ActivityOption = [
{ label: '全部活动', value: '全部活动' },
{ label: '双十一赢金币', value: '双十一赢金币' },
{ label: '充电桩铺设', value: '充电桩铺设' },
{ label: '1块钱升级月卡', value: '1块钱升级月卡' },
{ label: '免费充电1小时', value: '免费充电1小时' }
]
export const StatusOption = [
{ label: '全部状态', value: '全部状态' },
{ label: '未拓展', value: '未拓展' },
{ label: '已拓展', value: '已拓展' },
]
export const CityList = [
{
value: '330000',
areaLevel: 'province',
label: '浙江省',
children: [
{
value: '330100',
areaLevel: 'city',
label: '杭州市',
children: [],
},
],
},
{
value: '110000',
areaLevel: 'province',
label: '北京市',
children: [
{
value: '110000',
areaLevel: 'city',
label: '北京市',
children: [],
},
],
},
{
value: '120000',
areaLevel: 'province',
label: '天津市',
children: [
{
value: '120000',
areaLevel: 'city',
label: '天津市',
children: [],
},
],
},
{
value: '310000',
areaLevel: 'province',
label: '上海市',
children: [
{
value: '310000',
areaLevel: 'province',
label: '上海市',
children: [],
},
],
},
{
value: '440000',
areaLevel: 'province',
label: '广东省',
children: [
{
value: '440100',
areaLevel: 'city',
label: '广州市',
children: [],
},
{
value: '440300',
areaLevel: 'city',
label: '深圳市',
children: [],
},
{
value: '440400',
areaLevel: 'city',
label: '珠海市',
children: [],
},
{
value: '440600',
areaLevel: 'city',
label: '佛山市',
children: [],
},
{
value: '441300',
areaLevel: 'city',
label: '惠州市',
children: [],
},
{
value: '441900',
areaLevel: 'city',
label: '东莞市',
children: [],
},
{
value: '442000',
areaLevel: 'city',
label: '中山市',
children: [],
},
],
},
{
value: '130000',
areaLevel: 'province',
label: '河北省',
children: [
{
value: '130100',
areaLevel: 'city',
label: '石家庄市',
children: [],
},
{
value: '131000',
areaLevel: 'city',
label: '廊坊市',
children: [],
},
],
},
];

View File

@ -2,6 +2,7 @@ import { initWidgets } from './widgets';
import React, { useEffect, useMemo, useState } from 'react';
import { config } from './configs/config';
import { DipperContainer, IConfig } from '@antv/dipper';
import 'antd/dist/antd.css'
interface IInitData {
areaVOList: any[];
@ -21,7 +22,7 @@ export default function RumbMap() {
}, []);
return (
<div style={{ height: '100%', width:'100%', position:'absolute'}}>
<div style={{ height: '100%',width:'100%',position:'absolute'}}>
<DipperContainer<IInitData> cfg={mapConfig!} />
</div>
);

View File

@ -0,0 +1,25 @@
import { Select } from 'antd';
import React, { useState,useEffect } from 'react';
import { ActivityOption } from '../configs/mock';
const { Option } = Select
export function Activity() {
const [active,setActive] = useState<string>()
useEffect(()=>{
setActive(ActivityOption[0].value)
},[])
return(
<Select value={active} bordered={false}
onChange={(e)=> setActive(e)}>
{ ActivityOption.map((item)=>{
return(
<Option value={item.value} key={item.label}>{item.label}</Option>
)
})}
</Select>
)
}

View File

@ -0,0 +1,54 @@
.selectactivity {
padding: 0 0 20px 20px ;
}
.selectactivity .select {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.selectactivity .select .selectitem {
display: flex;
align-items: center;
width: 183px;
height: 64px;
margin: 0 15px 15px 0;
position: relative;
padding-left: 15px;
}
.selectactivity .select .selectitem .icon {
width: 40px;
height: 40px;
margin-right: 10px;
}
.selectactivity .select .selectitem .selecticon {
width: 21px;
height: 21px;
position: absolute;
right: 6px;
top: 6px;
}
.empty {
display: flex;
flex-direction: column;
align-items: center;
height: calc(674px - 80px);
justify-content: center;
}
.empty img {
width: 216px;
height: 132px;
margin-left: 100px;
}
.empty span {
color: rgba(0, 0, 0, 0.55);
margin-top: 20px;
}
.submit {
position: absolute;
bottom: 0;
right: 0;
}
.task {
height: calc(674px - 130px);
position: relative;
}

View File

@ -0,0 +1,91 @@
import React, { useState, useMemo } from 'react'
import { useLayerGroup } from '@antv/dipper'
import { Alert, Button, Select } from 'antd'
import { personOption, selectActivityItem } from '../../configs/mock'
import style from './index.module.css'
const { Option } = Select
export function ActivityTask() {
const selecticon = 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*kyI9T7Lrej4AAAAAAAAAAAAAARQnAQ'
const emptyicon = 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*H9dxSp69pi0AAAAAAAAAAAAAARQnAQ'
const { selectFeatures = [] } = useLayerGroup('grid')
const [current, setCurrent] = useState(selectActivityItem[0]?.value)
const selectItem = (item) => {
setCurrent(item)
}
const alertMsg = useMemo(() => {
if (selectFeatures.length === 2) {
return '勾选多个网格中,批量分配后将一起更新数据'
}
if (selectFeatures.length >= 3) {
return '你当前多选网格中包含已分配网格,无法批量分配,建议选择单个网格、或选择多个未分配网格的批量操作'
}
return '';
}, [JSON.stringify(selectFeatures)]);
const HasSelectFeature = () => {
return (
<div>
<div style={{ margin: '0 20px 20px' }}>
{selectFeatures.length >= 2 && <Alert
style={{ display:'flex', alignItems:'baseline' }}
message={alertMsg}
type="warning" showIcon
/>}
</div>
<div className={style.selectactivity}>
<h4></h4>
<div className={style.select}>
{selectActivityItem && selectActivityItem.map((item) => {
return (
<div key={item.label}
onClick={() => selectItem(item.value)}
style={{
border: current === item.value ? '1px solid #1E73F8' : '1px solid rgba(0,0,0,0.15)',
}}
className={style.selectitem}>
<img className={style.icon} src={item.icon} />
<span>{item.label}</span>
{current === item.value && <img className={style.selecticon} src={selecticon} />}
</div>
)
})}
</div>
</div>
<div style={{ margin: '0 20px' }}>
<h4></h4>
<Select mode="multiple" style={{ width: '100%' }}
showArrow defaultValue={['吴家豪', '周星星']}>
{personOption().map((item) => {
return (
<Option key={item.label} value={item.value}>{item.label}</Option>
)
})}
</Select>
</div>
<div className={style.submit}>
<Button style={{ marginRight: 8 }}></Button>
<Button type='primary'></Button>
</div>
</div>
)
}
const Empty = () => {
return (
<div className={style.empty}>
<img src={emptyicon} />
<span></span>
</div>
)
}
return (
<div className={style.task}>
{!selectFeatures.length ? <Empty /> : <HasSelectFeature />}
</div>
)
}

View File

@ -34,15 +34,43 @@ export function GridLayer() {
return layers.find((item: any) => item.type === 'gridLayer');
}, [layers]);
const testData = {
title: '图例',
items: [
{
colors: ['#fef0d9', '#fdcc8a', '#fc8d59', '#e34a33', '#b30000'],
title: '已分配',
},
{
colors: ['#f1eef6', '#bdc9e1', '#74a9cf', '#2b8cbe', '#045a8d'],
title: '未分配',
},
],
};
const updateLayerLegend = (items: any[]) => {
updateLegend('gridLayerLegend', {
type: 'discreteColor',
type: 'multiClassifyColor',
display: true,
position: 'bottomleft',
options: {
targetName: '区域类型',
title: '网格',
unkownName: layerProps.options.unkownName,
items,
items: [
{
colors: ['#BEC3BD', '#A1A6A0', '#828681', '#646763'],
title: '已分配',
},
{
colors: ['#CFE1B9', '#B0C298', '#90A276', '#718355'],
title: '未分配',
},
],
values: items.map((item) => {
return item.value.map((v) => {
return (v / 10000).toFixed(2);
});
}),
},
});
};
@ -70,10 +98,18 @@ export function GridLayer() {
return;
}
const color = ['#CFE1B9','#B0C298','#90A276','#718355']
const layer = new GridLayerGroup({
name: 'grid',
geodata: geoData,
options: layerProps.options,
data: geoData,
options: {
...layerProps.options,
fill:{
...layerProps.options.fill,
color
}
},
});
layerService.addLayer(layer);

View File

@ -0,0 +1,19 @@
.exhibititem {
display: flex;
align-items: center;
justify-content: space-between;
}
.exhibititem :global .ant-switch-checked {
background-color: #1E73F8;
}
.dropdown {
border-left: 1px solid #f3f3f3;
border-right: 1px solid #f3f3f3;
padding: 0 10px;
height: 32px;
line-height: 32px;
}
.dropicon {
padding-left: 8px;
color: rgba(0, 0, 0, 0.25);
}

View File

@ -0,0 +1,29 @@
import { DownOutlined } from "@ant-design/icons";
import { Dropdown, Menu, Switch } from "antd";
import React from "react";
import style from './index.module.css'
export function MapExhibit() {
const onChange = (e) => {
// TODO 根据业务实现
console.log(e)
}
const menu = (
<Menu>
<Menu.Item key="1">
<div className={style.exhibititem}>
<div style={{ marginRight: 50 }}></div>
<Switch defaultChecked size='small' onChange={onChange} />
</div>
</Menu.Item>
</Menu>
);
return (
<Dropdown overlay={menu}>
<div className={style.dropdown} >
<DownOutlined className={style.dropicon} />
</div>
</Dropdown>
)
}

View File

@ -0,0 +1,13 @@
.meahname {
padding: 20px;
}
.closeicon {
padding: 0 8px;
}
.edit {
display: flex;
align-items: center;
}
.edit span:hover {
color: #1890ff;
}

View File

@ -0,0 +1,83 @@
import React, { useRef, useState, useMemo, useCallback } from 'react';
import { CheckOutlined, CloseOutlined, EditOutlined } from '@ant-design/icons';
import styles from './index.module.css'
import { Input } from 'antd';
import { useLayerGroup } from '@antv/dipper';
export function MeshName() {
const { selectFeatures, updateProperties } = useLayerGroup('grid');
const [edit, setEdit] = useState(false);
const ref = useRef();
/**
* get meshname
* type []string
*/
const meshName = useMemo(() => {
if (!selectFeatures.length) return [];
return selectFeatures.map((item) => {
// @ts-ignore
return item.feature.properties.name;
});
}, [JSON.stringify(selectFeatures)]);
// 修改 网格名称
const editMeshName = useCallback(() => {
// @ts-ignore
const value = ref.current.state.value;
selectFeatures.forEach((item) => {
const properties = {
...item.feature.properties,
name: value,
};
updateProperties(item.feature, properties);
});
setEdit(false);
}, [JSON.stringify(selectFeatures)]);
// select more meshname 编辑 网格名称
const EditMeshName = () => {
return (
<>
{!edit ? (
<div onClick={() => setEdit(!edit)}>
<span>{meshName}</span>
<EditOutlined style={{ paddingLeft: 12 }}/>
</div>
) : (
<div className={styles.edit}>
<Input defaultValue={meshName} ref={ref} />
<CheckOutlined
onClick={editMeshName}
className={styles.closeicon}
/>
<CloseOutlined onClick={() => setEdit(false)} />
</div>
)}
</>
);
};
// show 多个网格名称
const ShowMeshNames = () => {
return (
<div>
{meshName.length >= 2 && meshName.map((s) => {
return (
<span key={s}>{s},</span>
)
})}
</div>
);
};
return (
<>
{meshName && meshName.length ? (
<div className={styles.meahname}>
{meshName.length === 1 ? <EditMeshName /> : <ShowMeshNames />}
</div>
) : null}
</>
);
}

View File

@ -0,0 +1,57 @@
import React from 'react';
export function MeshSplitSvg() {
return (
<div style={{ marginLeft: 4 }}>
<svg
width="16px"
height="20px"
viewBox="0 0 16 16"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.74074074,2.02 C8.01688312,2.02 8.24074074,2.24385763 8.24074074,2.52 L8.24,7.797 L13.5185185,7.79777778 C13.7946609,7.79777778 14.0185185,8.0216354 14.0185185,8.29777778 L14.0185185,14.0385185 C14.0185185,14.3146609 13.7946609,14.5385185 13.5185185,14.5385185 L2,14.5385185 C1.72385763,14.5385185 1.5,14.3146609 1.5,14.0385185 L1.5,2.52 C1.5,2.24385763 1.72385763,2.02 2,2.02 L7.74074074,2.02 Z M7.26727273,3.06 L2.54,3.06 L2.54,13.46 L12.94,13.46 L12.94,8.73272727 L7.267,8.732 L7.26727273,3.06 Z M14,1.5 C14.2761424,1.5 14.5,1.72385763 14.5,2 L14.5,6.2962963 C14.5,6.57243867 14.2761424,6.7962963 14,6.7962963 L9.7037037,6.7962963 C9.42756133,6.7962963 9.2037037,6.57243867 9.2037037,6.2962963 L9.2037037,2 C9.2037037,1.72385763 9.42756133,1.5 9.7037037,1.5 L14,1.5 Z M13.617284,2.38271605 L10.0864198,2.38271605 L10.0864198,5.91358025 L13.617284,5.91358025 L13.617284,2.38271605 Z"
id="形状结合"
fill="#333333"
></path>
</svg>
</div>
);
}
export function MeshMergeSvg() {
return (
<div style={{ marginLeft: 4 }}>
<svg
width="14px"
height="14px"
viewBox="0 0 14 14"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
>
<title></title>
<g
id="设计方案"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<g
id="兼容性播报中心"
transform="translate(-968.000000, -207.000000)"
>
<g id="自动合并" transform="translate(967.000000, 206.000000)">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<path
d="M10.3121824,7.30025029 L10.3121824,13.8 C10.3121824,13.9104569 10.2226393,14 10.1121824,14 L2.2,14 C2.08954305,14 2,13.9104569 2,13.8 L2,5.64440342 C2,5.53394647 2.08954305,5.44440342 2.2,5.44440342 L8.27622473,5.44440342 L8.27622473,5.44440342 L8.27622473,2.2 C8.27622473,2.08954305 8.36576778,2 8.47622473,2 L13.8,2 C13.9104569,2 14,2.08954305 14,2.2 L14,7.10025029 C14,7.21070724 13.9104569,7.30025029 13.8,7.30025029 L10.3121824,7.30025029 L10.3121824,7.30025029 Z"
id="路径-3"
stroke="#333333"
></path>
</g>
</g>
</g>
</svg>
</div>
);
}

View File

@ -0,0 +1,10 @@
.meshTools{
width: 32px;
height: 160px;
background: #fff;
border-radius: 2px;
display: flex;
flex-direction: column;
justify-content: space-between;
padding:15px 5px;
}

View File

@ -0,0 +1,82 @@
import React, { useMemo, useState, useRef } from 'react';
import styles from './index.module.css'
import { MeshSplitSvg, MeshMergeSvg } from './SvgElement';
import { useLayerGroup } from '@antv/dipper'
import { Input, message, Modal, Popconfirm, Tooltip } from 'antd';
export function MeshTools() {
const { selectFeatures = [] } = useLayerGroup('grid')
const [visible, setVisible] = useState(false)
const refs = useRef()
const disable = { cursor: 'pointer', opacity: 1 }
const noDisable = { cursor: 'not-allowed', opacity: 0.25 }
const cssPropsSplit = useMemo(() => {
if (selectFeatures.length === 1) return disable;
return noDisable;
}, [JSON.stringify(selectFeatures)]);
const cssPropsMerge = useMemo(() => {
if (selectFeatures.length >= 2) {
return disable
}
return noDisable;
}, [JSON.stringify(selectFeatures)]);
const splitMesh = () => {
// TODO 根据业务实现
}
const mergrMesh = () => {
// @ts-ignore
const value = refs.current.state.value
if (!value) {
return message.error('请输入要合并后的名称')
}
// TODO 根据业务实现
setVisible(false)
}
return (
<div className={styles.meshTools}>
<Tooltip placement="left"
title={selectFeatures.length === 1 ? '选择单个网格,可以拆分' : null}>
<Popconfirm
disabled={selectFeatures.length !== 1}
placement='left'
title='该网格将被拆分成xx个基础网格你确定要拆分吗'
onConfirm={splitMesh}
okText='确定'
trigger='click'
cancelText='取消'
>
<div style={{ ...cssPropsSplit }}>
<MeshSplitSvg />
<div style={{ width: 32 }}></div>
</div>
</Popconfirm>
</Tooltip>
<Tooltip placement='left'
title={selectFeatures.length >= 2 ? '选择多个网格,可以合并' : null}>
<div style={{ ...cssPropsMerge }} onClick={() => setVisible(true)}>
<MeshMergeSvg />
<div style={{ width: 32 }}></div>
</div>
</Tooltip>
<Modal title='网格合并'
okText='确认' cancelText='取消'
visible={visible} onOk={mergrMesh}
onCancel={() => setVisible(false)}
>
<h4></h4>
<Input ref={refs} placeholder='请输入名称' />
</Modal>
</div>
)
}

View File

@ -0,0 +1,11 @@
import { SaveOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import React from 'react';
export function Save() {
return (
<Button type="text" icon={<SaveOutlined />}>
</Button>
);
}

View File

@ -0,0 +1,60 @@
import React, { useState, useEffect } from "react";
import { Dropdown, Input, Menu, Select } from 'antd';
import { SearchOutlined } from "@ant-design/icons";
import { personOption } from "../configs/mock";
const { Search } = Input
const { Option } = Select
// 此功能 仅做展示,以实际业务为准
export function SearchPerson() {
const [persons, setPersons] = useState([])
const [visible, setVisible] = useState(false)
const onSearch = (e) => {
const value = e.target.value
setTimeout(() => {
if (value) {
setPersons(personOption())
setVisible(true)
} else {
setPersons([])
setVisible(false)
}
}, 300)
}
// 人员搜索
const onSelect = (value) =>{
// TODO 根据业务实现
}
const menu = (
<Menu>
<Menu.Item key="1">
{persons && persons.map((item) => {
return (
<div key={item.label}
onClick={()=>onSelect(item.value)}
style={{ paddingBottom: '5px' }}
>{item.label}</div>
)
})}
</Menu.Item>
</Menu>
);
return (
<div style={{ background:'#fff'}}>
<Dropdown overlay={menu} visible={visible}>
<Input bordered={false}
placeholder="搜索网格名称/人员名称"
prefix={<SearchOutlined />}
onChange={onSearch}
/>
</Dropdown>
</div>
)
}

View File

@ -0,0 +1,9 @@
import { SendOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import React from 'react';
export function Send() {
return(
<Button type='primary' icon={<SendOutlined rotate={-60} style={{color:'#fff'}}/>}></Button>
)
}

View File

@ -0,0 +1,25 @@
import { Select } from 'antd';
import React,{ useState,useEffect } from 'react';
import { StatusOption } from '../configs/mock';
const { Option } = Select
export function Status() {
const [status,setStatus] = useState<string>()
useEffect(()=>{
setStatus(StatusOption[0].value)
},[])
return(
<Select value={status} bordered={false}
onChange={(e)=> setStatus(e)}>
{ StatusOption.map((item)=>{
return(
<Option value={item.value} key={item.label}>{item.label}</Option>
)
})}
</Select>
)
}

View File

@ -0,0 +1,33 @@
import { registerWidget } from '@antv/dipper-core';
import {
CitySelect,
ClassifyColor,
DiscreteColor,
} from '@antv/dipper-widgets';
import { Activity } from './Activity';
import { ActivityTask } from './ActivityTask';
import { GridLayer } from './GridLayer';
import { MeshName } from './MeshName/index';
import { Save } from './Save';
import { SearchPerson } from './SearchPerson';
import { Send } from './Send';
import { Status } from './Status';
import { MeshTools } from './MeshTools';
import { MapExhibit } from './MapExhibit/index';
export function initWidgets() {
registerWidget('citySelect', CitySelect);
registerWidget('gridLayer', GridLayer);
registerWidget('classifyColor', ClassifyColor);
registerWidget('discreteColor', DiscreteColor);
registerWidget('meshName', MeshName);
registerWidget('meshTools',MeshTools)
registerWidget('save', Save);
registerWidget('publishbar', Send);
registerWidget('activity', Activity);
registerWidget('status',Status);
registerWidget('mapExhibit', MapExhibit);
registerWidget('searchPerson',SearchPerson)
registerWidget('activityTask',ActivityTask)
}

58
site/css/dipper.css Normal file
View File

@ -0,0 +1,58 @@
.dippercontainer {
display: flex;
align-items: center;
flex-direction: column;
height: 538px;
justify-content: center;
}
.title {
font-size: 30px;
font-family: 'PingFangSC-Semibold';
}
.subtitle {
font-size: 16px;
color: #697B8C;
font-family: 'PingFangSC-Regular';
padding-top: 20px;
}
.dipperdemo {
display: flex;
}
.dipperitem {
display: flex;
flex-direction: column;
align-items: center;
min-width: 400px;
max-width: 600px;
margin:40px 20px;
}
.dipperimg {
border-radius: 50%;
box-shadow: inset 0 0 16px 4px rgba(115, 108, 255, 0.44);
background-color: rgba(#746CFF, 0.24);
height: 180px;
width: 180px;
padding: 40px;
}
.dipperitem:hover .dipperimg{
padding: 32px;
border: 8px solid rgba(115, 108, 255, 0.08);
box-shadow: inset 0 0 16px 4px rgba(115, 108, 255, 0.44);
}
.dippertitle {
font-size: 24px;
font-family: 'PingFangSC-Semibold';
color: #0D1A26;
padding-top: 40px;
}
.dipperitem:hover .dippertitle {
color: #873BF4;
}

33
site/css/dippermap.css Normal file
View File

@ -0,0 +1,33 @@
.dippermapcontainer{
/* height: 656px; */
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: 68px;
}
.title {
font-size: 30px;
font-family: 'PingFangSC-Semibold';
}
.subtitle {
font-size: 16px;
color: #697B8C;
font-family: 'PingFangSC-Regular';
padding-top: 20px;
}
.carousel{
width: 80%;
padding-top: 36px;
}
.carousel img{
width: 100%;
height: 520px;
object-fit: cover;
}
.ant-carousel-vertical .slick-dots-right{
right: -40px !important;
top: 100px;
}

View File

@ -16,5 +16,8 @@
"深版精彩案例": "Dark Theme",
"感谢信赖":"WE ARE TRUSTED BY",
"新版发布" : "New Version",
"一个个真实的地理数据可视化案例,将复杂的地理数据,通过简单易用的API接口,让用户达到开箱即用的效果。" : "We have summarized a series of story design templates from lots of real geospatial data visualization cases, so that users can use them directly."
"一个个真实的地理数据可视化案例,将复杂的地理数据,通过简单易用的API接口,让用户达到开箱即用的效果。" : "We have summarized a series of story design templates from lots of real geospatial data visualization cases, so that users can use them directly.",
"指挥监控场景": "Command monitoring scene",
"指挥分配场景": "Command distribution scenario",
"可视化配置场景": "Visual configuration scenario"
}

View File

@ -1,7 +0,0 @@
import React from 'react';
const Page: React.FC & { noLayout: boolean } = () => <h1></h1>;
Page.noLayout = true;
export default Page;

View File

@ -6,75 +6,15 @@ import Features from '@antv/gatsby-theme-antv/site/components/Features';
import SEO from '@antv/gatsby-theme-antv/site/components/Seo';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useConfig } from './useConfig';
import { Dipper } from '../components/Dipper';
import { DipperMap } from '../components/DipperMap';
import '../css/home.css';
const IndexPage = () => {
const { t, i18n } = useTranslation();
const { L7Case, L7Features,notifications,companies, ecosystems} = useConfig();
const features = [
{
icon:
'https://gw.alipayobjects.com/zos/basement_prod/ca2168d1-ae50-4929-8738-c6df62231de3.svg',
title: t('架构灵活且自由'),
description: t('支持地图底图,渲染引擎,图层自由定制、扩展,组合'),
},
{
icon:
'https://gw.alipayobjects.com/zos/basement_prod/0ccf4dcb-1bac-4f4e-8d8d-f1031c77c9c8.svg',
title: t('业务专业且通用'),
description: t(
'以图形符号学地理设计体系理论基础,易用、易理解、专业、专注',
),
},
{
icon:
'https://gw.alipayobjects.com/zos/basement_prod/fd232581-14b3-45ec-a85c-fb349c51b376.svg',
title: t('视觉酷炫且动感'),
description: t('支持海量数据2D、3D动态可交互高性能渲染'),
},
];
const companies = [
{
name: '阿里云',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*V_xMRIvw2iwAAAAAAAAAAABkARQnAQ',
},
{
name: '支付宝',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*lYDrRZvcvD4AAAAAAAAAAABkARQnAQ',
},
{
name: '天猫',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*BQrxRK6oemMAAAAAAAAAAABkARQnAQ',
},
{
name: '淘宝网',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*1l8-TqUr7UcAAAAAAAAAAABkARQnAQ',
},
{
name: '网商银行',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*ZAKFQJ5Bz4MAAAAAAAAAAABkARQnAQ',
},
{
name: '盒马',
img:
'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*ePJMQZCb8vkAAAAAAAAAAABkARQnAQ',
},
{
name: 'yunos',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*_js7SaNosUwAAAAAAAAAAABkARQnAQ',
},
{
name: '菜鸟',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*TgV-RZDODJIAAAAAAAAAAABkARQnAQ',
},
];
const bannerButtons = [
{
text: t('图表示例'),
@ -87,43 +27,55 @@ const IndexPage = () => {
},
];
const notifications = [
const dipper = [
{
type: t('推荐'),
title: t('如何制作不一样的疫情世界地图-酷炫、动感的地理可视化'),
date: '2020.03.12',
link: 'https://www.yuque.com/antv/blog/wigku2',
title: t('配置化'),
image: 'https://gw.alipayobjects.com/zos/bmw-prod/a8d32053-ef9d-485e-ae13-2b49535e6f4f.svg',
link: `/${i18n.language}/view`
},
{
type: t('新版发布'),
title: t('L7 2.1 正式版'),
date: '2020.03.12',
link: ' https://www.yuque.com/antv/blog/ows55v',
title: t('组件化'),
image: 'https://gw.alipayobjects.com/zos/bmw-prod/4235cc53-ef5f-4a47-a33c-1623df19e4b7.svg',
link: `/${i18n.language}/task`
},
{
title: t('自由定制'),
image: 'https://gw.alipayobjects.com/zos/bmw-prod/29cbd68c-86ac-440c-a38d-792dbd8aea61.svg',
link: 'https://dippermap.alipay.com'
}
];
const cases = [
const dippermap = [
{
logo:
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*gjBmT56SDgsAAAAAAAAAAABkARQnAQ',
title: t('浅版精彩案例'),
description: t(
'一个个真实的地理数据可视化案例,将复杂的地理数据,通过简单易用的API接口,让用户达到开箱即用的效果。',
),
link: `/${i18n.language}/examples/gallery/basic`,
image:
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*h1vhT6eSVPkAAAAAAAAAAABkARQnAQ',
img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*6S8hQJAUB2oAAAAAAAAAAAAAARQnAQ',
alt: 'heat',
desc: '3D热力图',
},
{
logo:
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*gjBmT56SDgsAAAAAAAAAAABkARQnAQ',
title: t('深版精彩案例'),
description: t(
'一个个真实的地理数据可视化案例,将复杂的地理数据,通过简单易用的API接口,让用户达到开箱即用的效果。',
),
link: `/${i18n.language}/examples/gallery/basic`,
image:
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*-gtxQbUPoGQAAAAAAAAAAABkARQnAQ',
img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*R8juSLJc86wAAAAAAAAAAAAAARQnAQ',
alt: '3DARC',
desc: '3D曲线',
},
{
img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*MDmtT6lRS6EAAAAAAAAAAAAAARQnAQ',
alt: 'trip',
desc: '路径图',
},
{
img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*lRdLQotjkKsAAAAAAAAAAAAAARQnAQ',
alt: 'point',
desc: '3D柱图',
},
{
img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*W_DMQ5DVmIsAAAAAAAAAAAAAARQnAQ',
alt: 'polygon',
desc: '中国3D地图',
},
{
img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*InJXT6G-l6UAAAAAAAAAAAAAARQnAQ',
alt: 'hex',
desc: '六边形图',
},
];
@ -140,16 +92,19 @@ const IndexPage = () => {
}
title={t('L7 空间数据可视分析')}
description={t(
'蚂蚁金服 AntV 数据可视化团队推出的基于 WebGL 的开源大规模地理空间数据可视分析开发框架。',
'蚂蚁金服 AntV 数据可视化团队推出的基于 WebGL 的开源大规模地理空间数据可视分析引擎。',
)}
buttons={bannerButtons}
notifications={notifications}
className="banner"
githubStarLink="https://github.com/antvis/L7/stargazers"
/>
<Features features={features} style={{ width: '100%' }} />
<Cases cases={cases} />
<Features features={L7Features} style={{ width: '100%' }} />
<Dipper dipper={dipper} />
<Cases cases={L7Case} />
<DipperMap dippermap={dippermap} />
<Companies title={t('感谢信赖')} companies={companies} />
</>
);
};

View File

@ -1,2 +0,0 @@
import Index from './map.zh';
export default Index;

View File

@ -1,6 +1,6 @@
import React from 'react';
import Loadable from "@loadable/component"
const Map = Loadable(() => import("../components/rumbling"))
const Map = Loadable(() => import("../components/analysis"))
const Page: React.FC & { noLayout: boolean } = () => <Map/>;
Page.noLayout = true;

8
site/pages/task.en.tsx Normal file
View File

@ -0,0 +1,8 @@
import React from 'react';
import Loadable from "@loadable/component"
const Map = Loadable(() => import("../components/task"))
const Page: React.FC & { noLayout: boolean } = () => <Map/>;
Page.noLayout = true;
export default Page;

2
site/pages/task.zh.tsx Normal file
View File

@ -0,0 +1,2 @@
import Index from './task.en';
export default Index;

159
site/pages/useConfig.ts Normal file
View File

@ -0,0 +1,159 @@
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
export const useConfig = () => {
const { t, i18n } = useTranslation();
// 通知
const notifications = useMemo(() => {
return [{
type: t('推荐'),
title: t('如何制作不一样的疫情世界地图-酷炫、动感的地理可视化'),
date: '2020.03.12',
link: 'https://www.yuque.com/antv/blog/wigku2',
},
{
type: t('新版发布'),
title: t('L7 2.1 正式版'),
date: '2020.03.12',
link: ' https://www.yuque.com/antv/blog/ows55v',
},
];
}, []);
// L7 特性
const L7Features = useMemo(() => {
return [
{
icon:
'https://gw.alipayobjects.com/zos/basement_prod/ca2168d1-ae50-4929-8738-c6df62231de3.svg',
title: t('架构灵活且自由'),
description: t('支持地图底图,渲染引擎,图层自由定制、扩展,组合'),
},
{
icon:
'https://gw.alipayobjects.com/zos/basement_prod/0ccf4dcb-1bac-4f4e-8d8d-f1031c77c9c8.svg',
title: t('业务专业且通用'),
description: t(
'以图形符号学地理设计体系理论基础,易用、易理解、专业、专注',
),
},
{
icon:
'https://gw.alipayobjects.com/zos/basement_prod/fd232581-14b3-45ec-a85c-fb349c51b376.svg',
title: t('视觉酷炫且动感'),
description: t('支持海量数据2D、3D动态可交互高性能渲染'),
},
];
}, [])
const L7Case = useMemo(() => {
return [
{
logo:
'https://antv-2018.alipay.com/assets/image/icon/l7.svg',
title: t('指挥分配场景'),
description: t(
'区域化网格化数据管理指挥分配场景',
),
link: `/${i18n.language}/task`,
image:
'https://gw.alipayobjects.com/mdn/rms_08cc33/afts/img/A*CLJESKDO1g4AAAAAAAAAAAAAARQnAQ',
},
{
logo:
'https://antv-2018.alipay.com/assets/image/icon/l7.svg',
title: t('地图数据分析'),
description: t(
'区域化网格化数据分析场景',
),
link: `/${i18n.language}/view`,
image:
'https://gw.alipayobjects.com/mdn/rms_08cc33/afts/img/A*jb4tS7BiNo4AAAAAAAAAAAAAARQnAQ',
},
{
logo:
'https://gw.alipayobjects.com/zos/bmw-prod/222865fc-15e9-44b9-b726-444e1512d937.ico',
title: t('地理分析工具'),
description: t(
'地图可视化配置分析类场景',
),
link: `/${i18n.language}/examples/gallery/basic`,
image:
'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*MPWKQqh54vwAAAAAAAAAAAAAARQnAQ',
},
]
}, [])
const companies = useMemo(() => [{
name: '阿里云',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*V_xMRIvw2iwAAAAAAAAAAABkARQnAQ',
},
{
name: '支付宝',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*lYDrRZvcvD4AAAAAAAAAAABkARQnAQ',
},
{
name: '天猫',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*BQrxRK6oemMAAAAAAAAAAABkARQnAQ',
},
{
name: '淘宝网',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*1l8-TqUr7UcAAAAAAAAAAABkARQnAQ',
},
{
name: '网商银行',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*ZAKFQJ5Bz4MAAAAAAAAAAABkARQnAQ',
},
{
name: '盒马',
img:
'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*ePJMQZCb8vkAAAAAAAAAAABkARQnAQ',
},
{
name: 'yunos',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*_js7SaNosUwAAAAAAAAAAABkARQnAQ',
},
{
name: '菜鸟',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*TgV-RZDODJIAAAAAAAAAAABkARQnAQ',
}
], []);
const ecosystems = useMemo(() => [{
name: '阿里云',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*V_xMRIvw2iwAAAAAAAAAAABkARQnAQ',
},
{
name: '支付宝',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*lYDrRZvcvD4AAAAAAAAAAABkARQnAQ',
},
{
name: '天猫',
img:
'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*BQrxRK6oemMAAAAAAAAAAABkARQnAQ',
}
], []);
return {
ecosystems,
L7Features,
notifications,
companies,
L7Case,
}
}

2
site/pages/view.en.tsx Normal file
View File

@ -0,0 +1,2 @@
import Index from './view.zh';
export default Index;

8
site/pages/view.zh.tsx Normal file
View File

@ -0,0 +1,8 @@
import React from 'react';
import Loadable from "@loadable/component"
const Map = Loadable(() => import("../components/analysis"))
const Page: React.FC & { noLayout: boolean } = () => <Map/>;
Page.noLayout = true;
export default Page;