From 540014e8539bdf7ac15c094692bdee672c9c380b Mon Sep 17 00:00:00 2001 From: YiQianYao <42212176+2912401452@users.noreply.github.com> Date: Thu, 20 Jan 2022 20:21:39 +0800 Subject: [PATCH] Shihuidev (#944) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: pickbox 返回值增加选中id * style: lint style --- .../services/interaction/PickingService.ts | 6 +- packages/utils/src/geo.ts | 89 +++++ stories/Map/components/amap2demo_road.tsx | 279 ++++++++------ stories/Map/components/gridTile2.tsx | 340 ++++-------------- stories/Map/components/hot.tsx | 204 +++++++++++ stories/Map/components/hot2.tsx | 205 +++++++++++ stories/Map/components/linewall.tsx | 4 +- stories/Map/map.stories.tsx | 5 + 8 files changed, 758 insertions(+), 374 deletions(-) create mode 100644 stories/Map/components/hot.tsx create mode 100644 stories/Map/components/hot2.tsx diff --git a/packages/core/src/services/interaction/PickingService.ts b/packages/core/src/services/interaction/PickingService.ts index eb4ba979a3..94fcb2a222 100644 --- a/packages/core/src/services/interaction/PickingService.ts +++ b/packages/core/src/services/interaction/PickingService.ts @@ -138,7 +138,11 @@ export default class PickingService implements IPickingService { const pickedFeatureIdx = decodePickingColor(color); if (pickedFeatureIdx !== -1 && !featuresIdMap[pickedFeatureIdx]) { const rawFeature = layer.getSource().getFeatureById(pickedFeatureIdx); - features.push(rawFeature); + features.push({ + // @ts-ignore + ...rawFeature, + pickedFeatureIdx, + }); featuresIdMap[pickedFeatureIdx] = true; } } diff --git a/packages/utils/src/geo.ts b/packages/utils/src/geo.ts index 36cf05c4e3..aeb7c33cdb 100644 --- a/packages/utils/src/geo.ts +++ b/packages/utils/src/geo.ts @@ -250,3 +250,92 @@ export function bBoxToBounds(b1: BBox): IBounds { [b1[2], b1[3]], ]; } + +export function calDistance(p1: Point, p2: Point) { + return Math.sqrt(Math.pow(p1[0] - p2[0], 2) + Math.pow(p1[1] - p2[1], 2)); +} + +function dotMul(v1: Point, v2: Point) { + return v1[0] * v2[0] + v1[1] * v2[1]; +} + +function getMod(v: Point) { + return Math.sqrt(v[0] * v[0] + v[1] * v[1]); +} + +export function calAngle(v1: Point, v2: Point) { + return ( + (Math.acos(dotMul(v1, v2) / (getMod(v1) * getMod(v2))) * 180) / Math.PI + ); +} + +export function getAngle(v1: Point, v2: Point) { + // if(v2[0] < 0) { + // return calAngle(v1, v2) + 180 + // } else { + // return calAngle(v1, v2) + // } + + if (v2[0] > 0) { + if (v2[1] > 0) { + // 1 + return 90 - (Math.atan(v2[1] / v2[0]) * 180) / Math.PI; + } else { + // 2 + return 90 + (Math.atan(-v2[1] / v2[0]) * 180) / Math.PI; + } + } else { + if (v2[1] < 0) { + // 3 + return 180 + (90 - (Math.atan(v2[1] / v2[0]) * 180) / Math.PI); + } else { + // 4 + return 270 + (Math.atan(v2[1] / -v2[0]) * 180) / Math.PI; + } + } +} +interface IPathPoint { + start: Point; + end: Point; + dis: number; + rotation: number; + duration: number; +} + +export function flow(coords: Point[], time: number = 100) { + if (!coords || coords.length < 2) { + return; + } + const originVec2: Point = [0, 1]; + let totalDis = 0; + const path: IPathPoint[] = []; + for (let i = 0; i < coords.length - 1; i++) { + const p1: Point = coords[i]; + const p2: Point = coords[i + 1]; + const dis = calDistance(p1, p2); + totalDis += dis; + + const direct: Point = [p1[0] - p2[0], p1[1] - p2[1]]; + // const direct: Point = [p2[0] - p1[0], p2[1] - p1[1]]; + + let rotation = getAngle(originVec2, direct); + if (i > 0) { + const lastRotation = path[i - 1].rotation; + if (lastRotation - rotation > 360 - lastRotation + rotation) { + rotation = rotation + 360; + } + } + + path.push({ + start: p1, + end: p2, + dis, + rotation, + duration: 0, + }); + } + path.map((point) => { + point.duration = time * (point.dis / totalDis); + }); + return path; +} diff --git a/stories/Map/components/amap2demo_road.tsx b/stories/Map/components/amap2demo_road.tsx index 5f4a8973d1..adda64b0f1 100644 --- a/stories/Map/components/amap2demo_road.tsx +++ b/stories/Map/components/amap2demo_road.tsx @@ -1,7 +1,46 @@ -import { LineLayer, Scene, PointLayer } from '@antv/l7'; +import { + LineLayer, + Scene, + PointLayer, + flow, + MarkerLayer, + Marker, +} from '@antv/l7'; import { GaodeMap } from '@antv/l7-maps'; import * as React from 'react'; +import { animate, linear } from 'popmotion'; +interface IObject { + [key: string]: any; +} + +function parseCSV(data: string) { + let arr = data.split('\n'); + if (arr && arr[0]) { + let columns = arr[0].replace('\r', '').split(','); + let rows = arr.slice(1).map((d: string) => d.split(',')); + + let json = rows.map((row: string[]) => { + let object: IObject = {}; + row.map((e: string, i: number) => { + let str = e.replace('\r', ''); + let key = columns[i].replace('\n', ''); + // console.log('key', key) + object[key] = str; + return ''; + }); + return object; + }); + return json; + } + return []; +} + +function getLngLat(data: any) { + return data.map((d: any) => { + return [+d.lng, +d.lat]; + }); +} export default class Amap2demo_road extends React.Component { // @ts-ignore private scene: Scene; @@ -14,121 +53,155 @@ export default class Amap2demo_road extends React.Component { const scene = new Scene({ id: 'map', map: new GaodeMap({ - center: [120.1145, 30.221], - pitch: 50, - zoom: 16.8, - viewMode: '3D', + center: [116.35, 40], + zoom: 12, + // zoom: 3 }), }); this.scene = scene; - scene.on('loaded', () => { fetch( - 'https://gw.alipayobjects.com/os/bmw-prod/91d27a97-869a-459b-a617-498dcc9c3e7f.json', + 'https://gw.alipayobjects.com/os/bmw-prod/89aa8682-2245-448b-be0d-710308cd63a6.csv', ) - .then((res) => res.json()) + .then((res) => res.text()) .then((data) => { - scene.addImage( - 'road', - 'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*haGlTpW2BQgAAAAAAAAAAAAAARQnAQ', - ); - // @ts-ignore - const layer = new LineLayer() - .source(data) - .size(10) - .shape('line') - .texture('road') - .color('rgb(20, 180, 90)') - .animate({ - interval: 1, // 间隔 - duration: 1, // 持续时间,延时 - trailLength: 2, // 流线长度 - }) - .style({ - lineTexture: true, // 开启线的贴图功能 - iconStep: 200, // 设置贴图纹理的间距 - }); - scene.addLayer(layer); + const jsonData = parseCSV(data); + const lnglatData = getLngLat(jsonData); - scene.addImage( - 'start', - 'https://gw.alipayobjects.com/zos/bmw-prod/ebb0af57-4a8a-46e0-a296-2d51f9fa8007.svg', - ); - scene.addImage( - 'visitor', - 'https://gw.alipayobjects.com/zos/bmw-prod/64db255d-b636-4929-b072-068e75178b23.svg', - ); - scene.addImage( - 'museum', - 'https://gw.alipayobjects.com/zos/bmw-prod/0630591d-64db-4057-a04d-d65f43aebf0f.svg', - ); - scene.addImage( - 'supermarket', - 'https://gw.alipayobjects.com/zos/bmw-prod/ab42799d-dea6-4d37-bd62-3ee3e06bf6c0.svg', - ); - scene.addImage( - 'tower', - 'https://gw.alipayobjects.com/zos/bmw-prod/6d27cf89-638c-432b-a8c4-cac289ee98a8.svg', - ); - scene.addImage( - 'end', - 'https://gw.alipayobjects.com/zos/bmw-prod/59717737-5652-479f-9e6b-e7d2c5441446.svg', - ); - const imageLayer = new PointLayer() - .source( - [ - { - lng: 120.11025885601617, - lat: 30.22006389085372, - icon: 'start', - }, - { - lng: 120.11123578376913, - lat: 30.220443561196277, - icon: 'visitor', - }, - { - lng: 120.11408457779198, - lat: 30.22019805564678, - icon: 'museum', - }, - { - lng: 120.11683172384723, - lat: 30.21875509667716, - icon: 'supermarket', - }, - { - lng: 120.11945546294194, - lat: 30.218724022876376, - icon: 'tower', - }, - { - lng: 120.1184189041221, - lat: 30.21783201718256, - icon: 'end', - }, - ], + const sd = { + type: 'FeatureCollection', + name: 'dl2', + crs: { + type: 'name', + properties: { name: 'urn:ogc:def:crs:OGC:1.3:CRS84' }, + }, + features: [ { - parser: { - type: 'json', - x: 'lng', - y: 'lat', + type: 'Feature', + properties: {}, + geometry: { + type: 'MultiLineString', + coordinates: [ + [ + // [120.10236740112303, 30.25469303741397], + // [120.104341506958, 30.252542952311455], + // [120.10622978210449, 30.250096246503063], + // [120.10974884033202, 30.248613364842253], + // [120.11017799377441, 30.24661143909856], + // [120.11069297790527, 30.244387029323946], + // [120.11120796203613, 30.24245916678936], + // [120.11404037475586, 30.24156937132543], + // [120.11773109436037, 30.24194012041444], + // [120.12099266052248, 30.241865970708517], + // [120.12073516845703, 30.24053126643564], + // [120.12219429016112, 30.238455023761645], + // [120.12537002563475, 30.240086360983426], + // [120.12837409973145, 30.242533316047716], + // [120.12760162353517, 30.24661143909856], + // [120.12605667114256, 30.249503096524485], + // [120.12639999389648, 30.2540999151896], + // [120.12579917907715, 30.25521201642245], + // [120.12339591979979, 30.25521201642245], + // [120.12219429016112, 30.253729211980726], + // [120.11979103088379, 30.253877493432157], + // [120.11893272399901, 30.251282535717067], + // [120.11773109436037, 30.249280664359304], + // [120.11507034301759, 30.249058231690526], + + ...lnglatData, + + // [ + // 120.11507034301759, + // 30.249058231690526 + // ], + // [ + // 120.12, + // 30.249058231690526 + // ] + ], + ], }, }, - ) - .shape('icon', [ - 'start', - 'visitor', - 'museum', - 'supermarket', - 'tower', - 'end', - ]) - .size(35) + ], + }; + + const linelayer = new LineLayer({ blend: 'normal' }) + .source(sd) + .size(2) + .shape('line') + .color('#8C1EB2') + // .animate({ + // interval: 1, // 间隔 + // duration: 1, // 持续时间,延时 + // trailLength: 2, // 流线长度 + // }) .style({ - offsets: [0, 20], + // opacity: 'opacity', + sourceColor: '#f00', // 起点颜色 + targetColor: '#0f0', // 终点颜色 }); - scene.addLayer(imageLayer); + + linelayer.on('inited', () => { + const source = linelayer.getSource(); + const coords = source?.data?.dataArray[0]?.coordinates; + + const path = flow(coords, 50000); + + runPath(path, 0); + + // @ts-ignore + function runPath(pathData: any, startIndex: number) { + const path = pathData[startIndex]; + + if (!path) return; + const { start, end, duration, rotation } = path; + let startRotation = 360 - scene.getRotation(); + let timer0 = animate({ + from: { + rotation: startRotation, + }, + to: { + rotation: rotation, + }, + ease: linear, + duration: 600, + onUpdate: (o) => { + scene.setRotation(o.rotation); + }, + onComplete: () => { + timer0.stop(); + // @ts-ignore + timer0 = null; + + let timer = animate({ + from: { + lng: start[0], + lat: start[1], + }, + to: { + lng: end[0], + lat: end[1], + }, + ease: linear, + duration, + onUpdate: (o) => { + scene.setCenter([o.lng, o.lat]); + }, + onComplete: () => { + timer.stop(); + // @ts-ignore + timer = null; + setTimeout(() => { + runPath(pathData, startIndex + 1); + }, 500); + }, + }); + }, + }); + } + }); + + scene.addLayer(linelayer); }); }); } diff --git a/stories/Map/components/gridTile2.tsx b/stories/Map/components/gridTile2.tsx index 4550ab6252..0e470c6840 100644 --- a/stories/Map/components/gridTile2.tsx +++ b/stories/Map/components/gridTile2.tsx @@ -1,4 +1,4 @@ -import { LineLayer, Scene, PointLayer } from '@antv/l7'; +import { LineLayer, Scene, PointLayer, Marker, MarkerLayer } from '@antv/l7'; import { GaodeMap, GaodeMapV2, Map } from '@antv/l7-maps'; import * as React from 'react'; import { animate, easeInOut } from 'popmotion'; @@ -132,138 +132,15 @@ export default class GridTile2 extends React.Component { lat: 26.852646, }, ]; - const planeTarget = { - lng2: 111.616049, - lat2: 26.335053, - }; - const airLineData = [ - { - name: '常德桃花源机场', - lng: 111.641101, - lat: 28.91165, - ...planeTarget, - }, - { - name: '芷江机场', - lng: 109.709699, - lat: 27.442172, - ...planeTarget, - }, - { - name: '铜仁凤凰机场', - lng: 109.313971, - lat: 27.880629, - ...planeTarget, - }, - { - name: '桂林两江国际机场', - lng: 110.049256, - lat: 25.210065, - ...planeTarget, - }, - { - name: '长沙黄花国际机场', - lng: 113.216412, - lat: 28.183613, - ...planeTarget, - }, - { - name: '井冈山机场', - lng: 114.745845, - lat: 26.852646, - ...planeTarget, - }, - ]; scene.addImage( 'plane', 'https://gw.alipayobjects.com/zos/bmw-prod/96327aa6-7fc5-4b5b-b1d8-65771e05afd8.svg', ); - const airPrtsLayer = new PointLayer() - .source(airPorts, { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - }, - }) - .shape('name', 'text') - .color('rgb(22,119,255)') - .size(10); - - const airLineLayer = new LineLayer({ blend: 'normal' }) - .source(airLineData, { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - x1: 'lng2', - y1: 'lat2', - }, - }) - .shape('arc3d') - .size(1) - .color('#f00') - .style({ - sourceColor: 'rgb(22,119,255)', - targetColor: 'rgba(242,246,250,0.1)', - }); - - const airPlaneLayer = new LineLayer({ blend: 'normal', zIndex: 1 }) - .source(airLineData, { - parser: { - type: 'json', - x: 'lng2', - y: 'lat2', - x1: 'lng', - y1: 'lat', - }, - }) - .shape('arc3d') - .texture('plane') - .size(30) - .color('#f00') - .animate({ - duration: 0.2, - interval: 0.2, - trailLength: 0.2, - }) - .style({ - textureBlend: 'replace', - lineTexture: true, // 开启线的贴图功能 - iconStep: 6, // 设置贴图纹理的间距 - }); - - fetch( - 'https://gw.alipayobjects.com/os/bmw-prod/ec5351c9-d22b-4918-ad6c-1838064d3a64.json', - ) - .then((res) => res.json()) - .then((data) => { - const layer = new LineLayer({}) - .source(data) - .size(30000) - .shape('wall') - .style({ - opacity: 0.4, - sourceColor: '#0DCCFF', - targetColor: 'rbga(255,255,255, 0)', - heightfixed: true, - }); - // scene.addLayer(layer); - - const nameLayer = new PointLayer({ zIndex: 3 }) - .source(data) - .color('rgb(22,119,255)') - .size(15) - .shape('name', 'text'); - // scene.addLayer(nameLayer); - }); const img: HTMLImageElement = new Image(); img.crossOrigin = 'none'; img.src = - // 'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*UkvYRYS5jTAAAAAAAAAAAAAAARQnAQ'; - // 'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*6dzKS42L8_8AAAAAAAAAAAAAARQnAQ' 'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*dPgXQJ9eUtoAAAAAAAAAAAAAARQnAQ'; img.onload = function() { const data = getImageData(img); @@ -299,73 +176,51 @@ export default class GridTile2 extends React.Component { .color('rgb(22, 119, 255)') .style({ vertexHeightScale: 2000, - // opacity: 0.4, sourceColor: '#f00', targetColor: '#0f0', }); scene.addLayer(layer); }; - const waveLayer = new PointLayer({ zIndex: 2, blend: 'additive' }) + scene.addImage( + 'start', + 'https://gw.alipayobjects.com/zos/bmw-prod/ebb0af57-4a8a-46e0-a296-2d51f9fa8007.svg', + ); + const imageLayer = new PointLayer() .source( [ - { lng: 113, lat: 29, size: 10000 }, - { lng: 113.5, lat: 29.5, size: 30000 }, + { + lng: 111.641101, + lat: 28.91165, + cityData: '城市数据', + }, + ], + { + parser: { + type: 'json', + x: 'lng', + y: 'lat', + }, + }, + ) + .shape('cityData', 'text') + .size(16) + .style({ + textAnchor: 'left', // 文本相对锚点的位置 center|left|right|top|bottom|top-left + textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直] + spacing: 2, // 字符间距 + padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 + stroke: '#ffffff', // 描边颜色 + strokeWidth: 0.3, // 描边宽度 + strokeOpacity: 1.0, + }); + const pointLayer = new PointLayer() + .source( + [ { - lng: 110.23681640625, - lat: 29.64509464986076, - size: 74020.50373907911, - }, - { - lng: 115.01586914062499, - lat: 26.88777988202911, - size: 22908.885529976185, - }, - { - lng: 111.181640625, - lat: 28.724313406473463, - size: 73359.37302978932, - }, - { - lng: 112.686767578125, - lat: 29.257648503615542, - size: 18500.90838085843, - }, - { - lng: 114.664306640625, - lat: 28.98892237190413, - size: 20293.183968726793, - }, - { - lng: 113.90075683593749, - lat: 28.17855984939698, - size: 18051.412077639496, - }, - { - lng: 111.51123046875, - lat: 27.45466493898314, - size: 37645.94186119526, - }, - { - lng: 110.67626953125, - lat: 28.004101830368654, - size: 4214.588023703825, - }, - { - lng: 114.43359375, - lat: 29.477861195816843, - size: 61722.01580332115, - }, - { - lng: 110.445556640625, - lat: 26.96124577052697, - size: 70806.75519747598, - }, - { - lng: 113.75244140624999, - lat: 27.88278388425912, - size: 70930.24993464859, + lng: 111.641101, + lat: 28.91165, }, ], { @@ -377,96 +232,45 @@ export default class GridTile2 extends React.Component { }, ) .shape('circle') - .color('rgb(22, 119, 255)') - .size('size', (v) => v) - .animate(true) - .style({ - unit: 'meter', - }); + .size(35) + .color('#fff') + .style({}); + const height = 200; + const dom = document.createElement('div'); + dom.innerHTML = ` +