fix: pointlayer stroke 为零不能正常交互

This commit is contained in:
thinkinggis 2020-03-23 15:02:23 +08:00
parent 412e2a83f7
commit f3dbcea7ba
25 changed files with 1852 additions and 142 deletions

View File

@ -94,8 +94,11 @@
"rollup": "^1.27.14",
"rollup-plugin-analyzer": "^3.2.2",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-buble": "^0.19.8",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-postcss": "^2.0.3",
"rollup-plugin-terser": "^5.1.2",
"rollup-plugin-typescript": "^1.0.1",
"rollup-pluginutils": "^2.8.2",
"sass-loader": "^7.1.0",
"style-loader": "^1.0.0",
@ -180,5 +183,8 @@
"tnpm": {
"mode": "yarn"
},
"version": "0.0.0"
"version": "0.0.0",
"dependencies": {
"@turf/turf": "^5.1.6"
}
}

View File

@ -6,7 +6,7 @@ export interface IPopupOption {
closeButton: boolean;
closeOnClick: boolean;
maxWidth: string;
anchor: anchorType;
anchor: anchorType[any];
className: string;
offsets: number[];
}

View File

@ -4,6 +4,6 @@
## Usage
```
const draw = require('draw');
const draw = require('l7-draw');
```

View File

@ -1,12 +1,13 @@
{
"name": "@antv/l7-draw",
"version": "2.1.3",
"description": "Now Im the model of a modern major general / The venerated Virginian veteran whose men are all / Lining up, to put me up on a pedestal / Writin letters to relatives / Embellishin my elegance and eloquence / But the elephant is in the room / The truth is in ya face when ya hear the British cannons go / BOOM",
"description": "L7 Draw moudules",
"keywords": [],
"author": "thinkinggis <lzx199065@gmail.com>",
"license": "ISC",
"main": "lib/index.js",
"module": "es/index.js",
"unpkg": "dist/l7-draw.js",
"types": "es/index.d.ts",
"sideEffects": true,
"files": [
@ -33,7 +34,11 @@
},
"dependencies": {
"@antv/l7": "^2.1.3",
"@babel/runtime": "^7.7.7"
"@babel/runtime": "^7.7.7",
"@turf/circle": "^6.0.1",
"@turf/distance": "^6.0.1",
"@turf/helpers": "^6.1.4",
"lodash": "^4.6.2"
},
"bugs": {
"url": "https://github.com/antvis/L7/issues"

View File

@ -19,13 +19,9 @@ export default {
],
output: [
{
format: 'cjs',
file: pkg.main,
sourcemap: true
},
{
format: 'es',
file: pkg.module,
format: 'umd',
name: 'L7-Draw',
file: pkg.unpkg,
sourcemap: true
}
]

View File

@ -1 +1 @@
export { default as DrawSource } from './source';
export * from './modes/index';

View File

@ -1,22 +1,243 @@
import { ILayer } from '@antv/l7';
import DrawFeature from './draw_feature';
import {
IInteractionTarget,
ILayer,
ILngLat,
IPopup,
LineLayer,
PointLayer,
PolygonLayer,
Popup,
Scene,
} from '@antv/l7';
import turfCircle from '@turf/circle';
import turfDistance from '@turf/distance';
import { Feature, featureCollection, point } from '@turf/helpers';
import DrawFeature, { IDrawOption } from './draw_feature';
let CircleFeatureId = 0;
export type unitsType = 'degrees' | 'radians' | 'miles' | 'kilometers';
export interface IDrawCircleOption extends IDrawOption {
units: unitsType;
steps: number;
}
const InitFeature = {
type: 'FeatureCollection',
features: [],
};
export default class DrawCircle extends DrawFeature {
private center: [number, number];
private drawCircleLayer: ILayer;
protected onDragStart() {
private center: ILngLat;
private endPoint: ILngLat;
private dragStartPoint: ILngLat;
// 绘制完成之后显示
private normalLayer: ILayer;
private normalLineLayer: ILayer;
// 编辑过程中显示
private centerLayer: ILayer;
private circleLayer: ILayer;
private circleLineLayer: ILayer;
private currentFeature: Feature | null;
private popup: IPopup;
constructor(scene: Scene, options: Partial<IDrawCircleOption> = {}) {
super(scene, options);
this.initNormalLayer();
}
protected onDragStart = (e: IInteractionTarget) => {
// @ts-ignore
this.scene.map.dragdrag.disable();
}
protected onDragging() {
return;
this.scene.map.dragPan.disable();
this.dragStartPoint = e.lngLat;
if (this.drawStatus === 'DrawSelected') {
return;
}
this.center = e.lngLat;
const centerStyle = this.getStyle('active_point');
const layer = new PointLayer()
.source([this.center], {
parser: {
type: 'json',
x: 'lng',
y: 'lat',
},
})
.shape('circle')
.color(centerStyle.color)
.size(centerStyle.size)
.style(centerStyle.style);
this.scene.addLayer(layer);
this.initDrawLayer();
this.centerLayer = layer;
this.setCursor('grabbing');
};
protected getDefaultOptions() {
return {
steps: 4,
units: 'kilometres',
};
}
protected onDragEnd() {
protected onDragging = (e: IInteractionTarget) => {
if (this.drawStatus === 'DrawSelected') {
const delta = {
lng: e.lngLat.lng - this.dragStartPoint.lng,
lat: e.lngLat.lat - this.dragStartPoint.lat,
};
this.moveCircle(this.currentFeature as Feature, delta);
this.dragStartPoint = e.lngLat;
return;
}
this.endPoint = e.lngLat;
const currentData = this.createCircleData(this.center, this.endPoint);
this.updateDrawLayer(currentData);
this.addDrawPopup(this.endPoint, this.currentFeature?.properties?.radius);
return;
};
protected onDragEnd = () => {
if (this.drawStatus === 'DrawSelected') {
return;
}
this.source.addFeature(this.currentFeature);
// @ts-ignore
this.scene.map.dragPan.enable();
this.popup.remove();
// this.disable();
this.addCircleLayerEvent();
this.drawStatus = 'DrawSelected';
return;
};
protected onClick = () => {
return null;
};
protected onCircleLayerClick = () => {
if (this.currentFeature === null) {
return;
}
this.currentFeature = null;
this.updateNormalLayer();
this.centerLayer.setData([]);
this.circleLayer.setData(InitFeature);
this.circleLineLayer.setData(InitFeature);
return;
};
private createCircleData(center: ILngLat, endPoint: ILngLat) {
const radius = turfDistance(
point([center.lng, center.lat]),
point([endPoint.lng, endPoint.lat]),
this.getOption('units'),
);
const feature = turfCircle([center.lng, center.lat], radius, {
units: this.getOption('units'),
steps: this.getOption('steps'),
properties: {
id: `${CircleFeatureId++}`,
radius,
center,
endPoint,
},
});
this.currentFeature = feature as Feature;
return featureCollection([feature]);
}
protected onClick() {
return;
private initDrawLayer() {
const style = this.getStyle('active_fill');
const linestyle = this.getStyle('active_line');
this.circleLayer = new PolygonLayer()
.source(InitFeature)
.color(style.color)
.shape('fill')
.style(style.style);
this.circleLineLayer = new PolygonLayer()
.source(InitFeature)
.color(linestyle.color)
.size(linestyle.size)
.shape('line')
.style(linestyle.style);
this.scene.addLayer(this.circleLayer);
this.scene.addLayer(this.circleLineLayer);
}
private updateDrawLayer(currentData: any) {
this.circleLayer.setData(currentData);
this.circleLineLayer.setData(currentData);
}
private addDrawPopup(lnglat: ILngLat, dis: number) {
const popup = new Popup({
anchor: 'left',
closeButton: false,
})
.setLnglat(lnglat)
.setText(`${dis}`);
this.scene.addPopup(popup);
this.popup = popup;
}
private initNormalLayer() {
const style = this.getStyle('normal_fill');
const linestyle = this.getStyle('normal_line');
this.normalLayer = new PolygonLayer()
.source(this.source.data)
.shape('fill')
.active(true)
.color(style.color)
.style(style.style);
this.normalLineLayer = new LineLayer()
.source(this.source.data)
.shape('line')
.size(linestyle.size)
.color(linestyle.color)
.style(linestyle.style);
this.scene.addLayer(this.normalLayer);
this.scene.addLayer(this.normalLineLayer);
this.normalLayer.on('click', this.onNormalLayerClick);
}
private updateNormalLayer() {
this.normalLayer.setData(this.source.data);
this.normalLineLayer.setData(this.source.data);
}
private onNormalLayerClick = (e: any) => {
this.currentFeature = e.feature;
this.normalLayer.filter('id', (id: string) => {
return this.currentFeature === null || id !== e.feature.properties.id;
});
this.normalLineLayer.filter('id', (id: string) => {
return this.currentFeature === null || id !== e.feature.properties.id;
});
const seletedFeature = e.feature;
this.setCursor('move');
this.updateDrawLayer(featureCollection([seletedFeature]));
this.centerLayer.setData([seletedFeature.properties.center]);
this.drawStatus = 'DrawSelected';
this.enable();
};
private addCircleLayerEvent() {
this.circleLayer.on('mousemove', (e) => {
this.setCursor('move');
});
this.circleLayer.on('unmousemove', (e) => {
this.resetCursor();
});
this.circleLayer.on('unclick', this.onCircleLayerClick);
}
private moveCircle(feature: Feature, delta: ILngLat) {
const preCenter = feature?.properties?.center as ILngLat;
const preEndPoint = feature?.properties?.endPoint as ILngLat;
const newCenter = {
lng: preCenter.lng + delta.lng,
lat: preCenter.lat + delta.lat,
};
const newEndPoint = {
lng: preEndPoint.lng + delta.lng,
lat: preEndPoint.lat + delta.lat,
};
const newCircle = this.createCircleData(newCenter, newEndPoint);
this.centerLayer.setData([newCenter]);
this.updateDrawLayer(newCircle);
}
}

View File

@ -1,40 +1,83 @@
import { Scene } from '@antv/l7';
import { IInteractionTarget, Scene } from '@antv/l7';
import { Feature, FeatureCollection } from '@turf/helpers';
import { merge, throttle } from 'lodash';
import DrawSource from '../source';
import LayerStyles from '../util/layerstyle';
export interface IDrawOption {
data: FeatureCollection;
style: any;
}
export type DrawStatus = 'Drawing' | 'Selected' | 'Edit' | 'Finish';
export type DrawStatus =
| 'Drawing'
| 'DrawSelected'
| 'DrawEdit'
| 'DrawFinish'
| 'EditFinish';
export default abstract class DrawFeature {
private source: DrawSource;
private scene: Scene;
constructor(scene: Scene, options: IDrawOption) {
protected source: DrawSource;
protected scene: Scene;
protected options: {
[key: string]: any;
} = {
style: LayerStyles,
};
protected drawStatus: DrawStatus = 'Drawing';
private isEnable: boolean = false;
constructor(scene: Scene, options: Partial<IDrawOption> = {}) {
const { data } = options;
this.scene = scene;
this.source = new DrawSource(data);
this.options = merge(this.options, this.getDefaultOptions(), options);
}
public enable() {
if (this.isEnable) {
return;
}
this.scene.on('dragstart', this.onDragStart);
this.scene.on('drag', this.onDragging);
this.scene.on('dragging', this.onDragging);
this.scene.on('dragend', this.onDragEnd);
this.scene.on('click', this.onClick);
// this.scene.on('click', this.onClick);
this.setCursor('crosshair');
}
public disable() {
this.scene.off('dragstart', this.onDragStart);
this.scene.off('drag', this.onDragging);
this.scene.off('dragging', this.onDragging);
this.scene.off('dragend', this.onDragEnd);
this.scene.off('click', this.onClick);
// this.scene.off('click', this.onClick);
this.resetCursor();
}
protected getDefaultOptions() {
return {};
}
protected abstract onDragStart(): any;
protected abstract onDragStart(e: IInteractionTarget): void;
protected abstract onDragging(): any;
protected abstract onDragging(e: IInteractionTarget): void;
protected abstract onDragEnd(): any;
protected abstract onDragEnd(e: IInteractionTarget): void;
protected abstract onClick(): any;
protected abstract onClick(): void;
protected getOption(key: string) {
return this.options[key];
}
protected getStyle(id: string) {
return this.getOption('style')[id];
}
protected setCursor(cursor: string) {
const container = this.scene.getContainer();
if (container) {
container.style.cursor = cursor;
}
}
protected resetCursor() {
const container = this.scene.getContainer();
if (container) {
container.style.cursor = 'default';
}
}
}

View File

@ -0,0 +1,2 @@
import DrawCircle from './draw_circle';
export { DrawCircle };

View File

@ -1,6 +1,6 @@
import { Feature, FeatureCollection } from '@turf/helpers';
export default class DrawSource {
private data: FeatureCollection;
public data: FeatureCollection;
constructor(data?: FeatureCollection) {
this.data = data || this.getDefaultData();
}

View File

@ -1,4 +1,4 @@
const FillStyle = {
const LayerStyles = {
// 正常显示样式
normal_fill: {
type: 'PolygonLayer',
@ -17,8 +17,6 @@ const FillStyle = {
opacity: 0.1,
},
},
};
const PointStyle = {
normal_point: {
type: 'PointLayer',
shape: 'circle',
@ -46,8 +44,6 @@ const PointStyle = {
strokeWidth: 2,
},
},
};
const LineStyle = {
normal_line: {
type: 'LineLayer',
shape: 'line',
@ -69,3 +65,5 @@ const LineStyle = {
},
},
};
export default LayerStyles;

View File

View File

@ -51,11 +51,13 @@ export default class DataMappingPlugin implements ILayerPlugin {
filterData = dataArray.filter((record: IParseDataItem) => {
return this.applyAttributeMapping(filter, record)[0];
});
filter.needRemapping = false;
}
if (attributesToRemapping.length) {
// 过滤数据
if (filter?.needRemapping) {
layer.setEncodedData(this.mapping(attributes, filterData));
filter.needRemapping = false;
} else {
layer.setEncodedData(
this.mapping(

View File

@ -57,6 +57,8 @@ void main() {
float opacity_t = smoothstep(0.0, antialiased_blur, outer_df);
if(u_stroke_width <0.01 ) {
gl_FragColor = v_color * opacity_t;
gl_FragColor.a = gl_FragColor.a * u_opacity;
gl_FragColor = filterColor(gl_FragColor);
return;
}
float color_t = u_stroke_width < 0.01 ? 0.0 : smoothstep(

View File

@ -5,8 +5,10 @@
"main": "lib/index.js",
"module": "es/index.js",
"types": "es/index.d.ts",
"unpkg": "dist/l7-maps.js",
"sideEffects": false,
"files": [
"dist",
"lib",
"es",
"typings/index.d.ts",

View File

@ -0,0 +1,29 @@
import pkg from './package.json';
import typescript from 'rollup-plugin-typescript';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import buble from 'rollup-plugin-buble';
export default {
input: './src/index.ts',
plugins: [
typescript({
exclude: 'node_modules/**',
typescript: require('typescript')
}),
resolve(),
commonjs(),
buble({
transforms: { generator: false }
})
],
output: [
{
format: 'umd',
name: 'L7-Maps',
file: pkg.unpkg,
sourcemap: true
}
]
};

View File

@ -1,11 +1,10 @@
# `react`
> TODO: description
> L7
## Usage
```
const react = require('react');
import { Scene } from '@antv/l7-react';
// TODO: DEMONSTRATE API
```

View File

@ -264,6 +264,9 @@ class Scene
this.mapService.panTo(pixel);
}
public getContainer() {
return this.mapService.getContainer();
}
public setZoom(zoom: number): void {
this.mapService.setZoom(zoom);
}

View File

@ -9,7 +9,7 @@ export enum anchorType {
'RIGHT' = 'right',
}
export const anchorTranslate = {
export const anchorTranslate: { [key: string]: string } = {
center: 'translate(-50%,-50%)',
top: 'translate(-50%,0)',
'top-left': 'translate(0,0)',

View File

@ -40,7 +40,7 @@ function sum(x: number[]) {
}
// Initializing the sum as the first number in the array
let sumNum = x[0];
let sumNum = x[0] * 1;
// Keeping track of the floating-point error correction
let correction = 0;
@ -71,16 +71,45 @@ function mean(x: number[]) {
return sum(x) / x.length;
}
export { sum, max, min, mean };
function mode(x: any[]) {
if (x.length === 0) {
throw new Error('mean requires at least one data point');
}
if (x.length < 3) {
return x[0];
}
x.sort();
let last = x[0];
let value = NaN;
let maxSeen = 0;
let seenThis = 1;
for (let i = 1; i < x.length + 1; i++) {
if (x[i] !== last) {
if (seenThis > maxSeen) {
maxSeen = seenThis;
value = last;
}
seenThis = 1;
last = x[i];
} else {
seenThis++;
}
}
return value;
}
export { sum, max, min, mean, mode };
export const statMap: { [key: string]: any } = {
min,
max,
mean,
sum,
mode,
};
export function getColumn(data: IItemData[], columnName: string) {
return data.map((item: IItemData) => {
return item[columnName] * 1;
return item[columnName];
});
}

View File

@ -0,0 +1,45 @@
import { LineLayer, PointLayer, PolygonLayer, Popup, Scene } from '@antv/l7';
import { DrawCircle } from '@antv/l7-draw';
import { GaodeMap, Mapbox } from '@antv/l7-maps';
import * as React from 'react';
export default class Circle extends React.Component {
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new Mapbox({
pitch: 0,
style: 'normal',
center: [121.775374, 31.31067],
zoom: 15,
}),
});
this.scene = scene;
scene.on('loaded', () => {
const drawCircle = new DrawCircle(scene);
drawCircle.enable();
});
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -55,7 +55,7 @@ export default class MultiPolygon extends React.Component {
scene.addLayer(circleLayer);
scene.on('dragstart', (e: any) => {
// @ts-ignore
scene.map.dragdrag.disable();
scene.map.drag.disable();
startPoint = e.lngLat;
const layer = new PointLayer()
.source([startPoint], {

View File

@ -1,10 +1,12 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import Circle from './Components/Circle';
import DrawCircle from './Components/DrawCircle';
import DrawPolygon from './Components/DrawPolygon';
import DrawRect from './Components/DrawRect';
storiesOf('绘制', module)
.add('圆', () => <Circle />, {})
.add('绘制圆', () => <DrawCircle />, {})
.add('四边形', () => <DrawRect />, {})
.add('绘制面', () => <DrawPolygon />, {});

View File

@ -2,8 +2,6 @@ import { HeatmapLayer, PointLayer, Scene } from '@antv/l7';
import { GaodeMap, Mapbox } from '@antv/l7-maps';
import * as dat from 'dat.gui';
import * as React from 'react';
// @ts-ignore
import data from '../data/data.json';
export default class HexagonLayerDemo extends React.Component {
// @ts-ignore
private scene: Scene;
@ -16,87 +14,48 @@ export default class HexagonLayerDemo extends React.Component {
}
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/337ddbb7-aa3f-4679-ab60-d64359241955.json',
);
const pointsData = await response.json();
const scene = new Scene({
id: 'map',
map: new GaodeMap({
center: [120.19382669582967, 30.258134],
map: new Mapbox({
pitch: 0,
style: 'light',
zoom: 3,
style: 'blank',
center: [140.067171, 36.26186],
zoom: 0,
maxZoom: 0,
}),
});
const pointLayer = new HeatmapLayer({})
.source(pointsData, {
transforms: [
{
type: 'grid',
size: 500000,
field: 'capacity',
method: 'sum',
},
],
})
.shape('hexagon')
.style({
coverage: 0.9,
angle: 0,
opacity: 0.6,
})
.color(
'sum',
[
'#3F4BBA',
'#3F4BBA',
'#3F4BBA',
'#3F4BBA',
'#3C73DA',
'#3C73DA',
'#3C73DA',
'#0F62FF',
'#0F62FF',
'#30B2E9',
'#30B2E9',
'#40C4CE',
].reverse(),
);
scene.addLayer(pointLayer);
pointLayer.on('click', (e) => {
console.log(e);
});
this.scene = scene;
const gui = new dat.GUI();
this.gui = gui;
const styleOptions = {
textAnchor: 'center',
strokeWidth: 1,
};
const rasterFolder = gui.addFolder('栅格可视化');
rasterFolder
.add(styleOptions, 'textAnchor', [
'center',
'left',
'right',
'top',
'bottom',
'top-left',
'bottom-right',
'bottom-left',
'top-right',
])
.onChange((anchor: string) => {
pointLayer.style({
textAnchor: anchor,
scene.on('loaded', () => {
fetch(
'https://gw.alipayobjects.com/os/bmw-prod/3dadb1f5-8f54-4449-8206-72db6e142c40.json',
)
.then((res) => res.json())
.then((data) => {
const pointLayer = new HeatmapLayer({
autoFit: true,
})
.source(data, {
transforms: [
{
type: 'hexagon',
size: 500000,
field: 'name',
method: 'mode',
},
],
})
.shape('hexagon') // 支持 circle, hexagon,triangle
.color('mode', ['#ffffe5','#fff7bc','#fee391','#fec44f','#fe9929','#ec7014','#cc4c02','#993404','#662506'])
.active(false)
.style({
coverage: 0.7,
// angle: 0.5,
opacity: 1.0,
});
scene.addLayer(pointLayer);
console.log(pointLayer.getSource());
this.scene = scene;
});
scene.render();
});
// });
});
}
public render() {

1391
yarn.lock

File diff suppressed because it is too large Load Diff