Merge branch 'feat-layer-repaint' into 'master'
Feat layer repaint 增加图层更新机制 See merge request !24
|
@ -0,0 +1,106 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<meta name="geometry" content="diagram">
|
||||||
|
<link rel="stylesheet" href="./assets/common.css">
|
||||||
|
<link rel="stylesheet" href="./assets/info.css">
|
||||||
|
<title>point_circle</title>
|
||||||
|
<style>
|
||||||
|
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||||
|
.amap-maps {
|
||||||
|
cursor: auto !important
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="map"></div>
|
||||||
|
<script src="https://webapi.amap.com/maps?v=1.4.8&key=15cd8a57710d40c9b7c0e3cc120f1200&plugin=Map3D"></script>
|
||||||
|
<script src="./assets/jquery-3.2.1.min.js"></script>
|
||||||
|
<script src="./assets/dat.gui.min.js"></script>
|
||||||
|
<script src="../build/L7.js"></script>
|
||||||
|
<script>
|
||||||
|
var radius = 0.2;
|
||||||
|
|
||||||
|
function pointOnCircle(angle) {
|
||||||
|
return {
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
120.19382669582967 + Math.cos(angle) * radius,
|
||||||
|
30.258134 + Math.sin(angle) * radius
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(pointOnCircle(10))
|
||||||
|
const scene = new L7.Scene({
|
||||||
|
id: 'map',
|
||||||
|
mapStyle: 'light', // 样式URL
|
||||||
|
center: [ 120.19382669582967, 30.258134 ],
|
||||||
|
pitch: 0,
|
||||||
|
zoom: 2,
|
||||||
|
maxZoom:20,
|
||||||
|
hash:true,
|
||||||
|
minZoom:0,
|
||||||
|
});
|
||||||
|
window.scene = scene;
|
||||||
|
scene.on('loaded', () => {
|
||||||
|
const circleLayer = scene.PointLayer({
|
||||||
|
zIndex: 0,
|
||||||
|
})
|
||||||
|
.source(pointOnCircle(0))
|
||||||
|
.shape('circle')
|
||||||
|
.size(10) // default 1
|
||||||
|
.active(true)
|
||||||
|
.color('#2894E0')
|
||||||
|
.style({
|
||||||
|
stroke: 'rgb(255,255,255)',
|
||||||
|
strokeWidth: 1,
|
||||||
|
opacity: 0.8
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
|
||||||
|
function animateMarker(timestamp) {
|
||||||
|
|
||||||
|
circleLayer.setData(pointOnCircle(timestamp / 1000));
|
||||||
|
requestAnimationFrame(animateMarker);
|
||||||
|
}
|
||||||
|
animateMarker(0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
const layerText = scene.PointLayer({
|
||||||
|
zIndex: 3
|
||||||
|
})
|
||||||
|
.source(circleLayer.layerSource)
|
||||||
|
.shape('point_count', 'text')
|
||||||
|
.active(true)
|
||||||
|
.size('point_count', [ 0, 16]) // default 1
|
||||||
|
.color('#f00')
|
||||||
|
.style({
|
||||||
|
stroke: '#999',
|
||||||
|
strokeWidth: 0,
|
||||||
|
opacity: 1.0
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
console.log(layerText);
|
||||||
|
|
||||||
|
});
|
||||||
|
**/
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<script src="../build/L7.js"></script>
|
<script src="../build/L7.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const colorObj ={
|
const colorObj ={
|
||||||
blue: ["#E8FCFF", "#CFF6FF", "#A1E9ff", "#65CEF7", "#3CB1F0", "#2894E0", "#1772c2", "#105CB3", "#0D408C", "#002466"].reverse(),
|
blue: ["#E8FCFF", "#CFF6FF", "#A1E9ff", "#65CEF7", "#3CB1F0", "#2894E0", "#1772c2", "#105CB3", "#0D408C", "#002466"],
|
||||||
red: ["#FFF4F2", "#FFDFDB", "#FAADAA", "#F77472", "#F04850", "#D63147", "#BD223E", "#A81642", "#820C37", "#5C0023"].reverse(),
|
red: ["#FFF4F2", "#FFDFDB", "#FAADAA", "#F77472", "#F04850", "#D63147", "#BD223E", "#A81642", "#820C37", "#5C0023"].reverse(),
|
||||||
orange:["#FFF7EB", "#FFECD4", "#FAD09D", "#F7B16A", "#F08D41", "#DB6C2C", "#C2491D", "#AD2B11", "#871D0C", "#610800"].reverse(),
|
orange:["#FFF7EB", "#FFECD4", "#FAD09D", "#F7B16A", "#F08D41", "#DB6C2C", "#C2491D", "#AD2B11", "#871D0C", "#610800"].reverse(),
|
||||||
green:["#FAFFF0", "#EBF7D2", "#C8E695", "#A5D660", "#7DC238", "#59A616", "#3F8C0B", "#237804", "#125200", "#082B00"].reverse(),
|
green:["#FAFFF0", "#EBF7D2", "#C8E695", "#A5D660", "#7DC238", "#59A616", "#3F8C0B", "#237804", "#125200", "#082B00"].reverse(),
|
||||||
|
@ -35,43 +35,53 @@ const colorObj ={
|
||||||
|
|
||||||
const scene = new L7.Scene({
|
const scene = new L7.Scene({
|
||||||
id: 'map',
|
id: 'map',
|
||||||
mapStyle: 'light', // 样式URL
|
mapStyle: 'dark', // 样式URL
|
||||||
center: [ 120.19382669582967, 30.258134 ],
|
center: [ 120.19382669582967, 30.258134 ],
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
zoom: 12,
|
zoom: 12,
|
||||||
maxZoom:14,
|
maxZoom:20,
|
||||||
minZoom:11,
|
minZoom:0,
|
||||||
});
|
});
|
||||||
window.scene = scene;
|
window.scene = scene;
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
$.get('https://gw.alipayobjects.com/os/rmsportal/epnZEheZeDgsiSjSPcCv.json', data => {
|
$.get('https://gw.alipayobjects.com/os/rmsportal/epnZEheZeDgsiSjSPcCv.json', data => {
|
||||||
const circleLayer = scene.PointLayer({
|
const circleLayer = scene.PointLayer({
|
||||||
zIndex: 2,
|
zIndex: 0,
|
||||||
})
|
})
|
||||||
.source(data)
|
.source(data,{
|
||||||
.shape('circle')
|
isCluster:true
|
||||||
.size('value', [ 2, 30]) // default 1
|
|
||||||
.scale('value', {
|
|
||||||
type:'log',
|
|
||||||
})
|
})
|
||||||
|
.shape('hexagon')
|
||||||
|
.size('point_count', [ 5, 40]) // default 1
|
||||||
//.size('value', [ 10, 300]) // default 1
|
//.size('value', [ 10, 300]) // default 1
|
||||||
.active(true)
|
.active(true)
|
||||||
.filter('value', field_8 => {
|
.color('point_count',colorObj.blue)
|
||||||
return field_8 * 1 > 500;
|
|
||||||
})
|
|
||||||
.color('type', colorObj.blue)
|
|
||||||
.style({
|
.style({
|
||||||
stroke: 'rgb(255,255,255)',
|
stroke: 'rgb(255,255,255)',
|
||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
opacity: 1.
|
opacity: 1
|
||||||
})
|
})
|
||||||
.render();
|
.render();
|
||||||
console.log(circleLayer);
|
window.circleLayer = circleLayer;
|
||||||
var a = circleLayer.getLegendCfg('type','color');
|
const layerText = scene.PointLayer({
|
||||||
console.log(a);
|
zIndex: 3
|
||||||
circleLayer.on('click',(e)=>{
|
})
|
||||||
console.log(e);
|
.source(circleLayer.layerSource)
|
||||||
})
|
.shape('point_count', 'text')
|
||||||
|
.active(true)
|
||||||
|
.filter('point_count',(p)=>{
|
||||||
|
return p > 50
|
||||||
|
})
|
||||||
|
.size('point_count', [ 5, 20]) // default 1
|
||||||
|
.color('#fff')
|
||||||
|
.style({
|
||||||
|
stroke: '#999',
|
||||||
|
strokeWidth: 0,
|
||||||
|
opacity: 1.0
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
console.log(layerText);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<meta name="geometry" content="diagram">
|
||||||
|
<link rel="stylesheet" href="./assets/common.css">
|
||||||
|
<link rel="stylesheet" href="./assets/info.css">
|
||||||
|
<title>animateLine</title>
|
||||||
|
<style>
|
||||||
|
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||||
|
.amap-maps {
|
||||||
|
cursor: auto !important
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="map"></div>
|
||||||
|
<script src="https://webapi.amap.com/maps?v=1.4.8&key=15cd8a57710d40c9b7c0e3cc120f1200&plugin=Map3D"></script>
|
||||||
|
<script src="./assets/jquery-3.2.1.min.js"></script>
|
||||||
|
<script src="./assets/dat.gui.min.js"></script>
|
||||||
|
<script src="../build/L7.js"></script>
|
||||||
|
<script>
|
||||||
|
var geojson = {
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": [{
|
||||||
|
"type": "Feature",
|
||||||
|
"geometry": {
|
||||||
|
"type": "LineString",
|
||||||
|
"coordinates": [
|
||||||
|
[0, 0],
|
||||||
|
[0.001, 0.0001]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
};
|
||||||
|
var speedFactor = 30; // number of frames per longitude degree
|
||||||
|
var animation; // to store and cancel the animation
|
||||||
|
var startTime = 0;
|
||||||
|
var progress = 0; // progress = timestamp - startTime
|
||||||
|
var resetTime = false; // indicator of whether time reset is needed for the animation
|
||||||
|
var pauseButton = document.getElementById('pause');
|
||||||
|
const scene = new L7.Scene({
|
||||||
|
id: 'map',
|
||||||
|
mapStyle: 'light', // 样式URL
|
||||||
|
center: [ 120.19382669582967, 30.258134 ],
|
||||||
|
pitch: 0,
|
||||||
|
zoom: 2,
|
||||||
|
maxZoom:20,
|
||||||
|
minZoom:0,
|
||||||
|
});
|
||||||
|
scene.on('loaded', () => {
|
||||||
|
const linelayer = scene.LineLayer({
|
||||||
|
zIndex: 2
|
||||||
|
})
|
||||||
|
.source(geojson)
|
||||||
|
.size([2,1])
|
||||||
|
.shape('line')
|
||||||
|
.color( "#2894E0")
|
||||||
|
.render();
|
||||||
|
startTime = performance.now();
|
||||||
|
animateLine(0);
|
||||||
|
function animateLine(timestamp) {
|
||||||
|
if (resetTime) {
|
||||||
|
// resume previous progress
|
||||||
|
startTime = performance.now() - progress;
|
||||||
|
resetTime = false;
|
||||||
|
} else {
|
||||||
|
progress = timestamp - startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// restart if it finishes a loop
|
||||||
|
if (progress > speedFactor * 360) {
|
||||||
|
startTime = timestamp;
|
||||||
|
geojson.features[0].geometry.coordinates = [
|
||||||
|
[0, 0],
|
||||||
|
[0.001, 0.0001]
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
var x = progress / speedFactor;
|
||||||
|
// draw a sine wave with some math.
|
||||||
|
var y = Math.sin(x * Math.PI / 90) * 40;
|
||||||
|
// append new coordinates to the lineString
|
||||||
|
|
||||||
|
geojson.features[0].geometry.coordinates.push([x, y]);
|
||||||
|
// then update the map
|
||||||
|
linelayer.setData(geojson);
|
||||||
|
}
|
||||||
|
// Request the next frame of the animation.
|
||||||
|
animation = requestAnimationFrame(animateLine);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 564 KiB After Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 194 KiB |
After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 528 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 71 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 73 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 73 KiB |
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@antv/l7",
|
"name": "@antv/l7",
|
||||||
"version": "1.1.7",
|
"version": "1.1.8",
|
||||||
"description": "Large-scale WebGL-powered Geospatial Data Visualization",
|
"description": "Large-scale WebGL-powered Geospatial Data Visualization",
|
||||||
"main": "build/l7.js",
|
"main": "build/l7.js",
|
||||||
"browser": "build/l7.js",
|
"browser": "build/l7.js",
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
import TinySDF from '@mapbox/tiny-sdf';
|
||||||
|
import { buildMapping } from '../../util/font-util';
|
||||||
|
import * as THREE from '../../core/three';
|
||||||
|
import LRUCache from '../../util/lru-cache';
|
||||||
|
export const DEFAULT_CHAR_SET = getDefaultCharacterSet();
|
||||||
|
export const DEFAULT_FONT_FAMILY = 'sans-serif';
|
||||||
|
export const DEFAULT_FONT_WEIGHT = 'normal';
|
||||||
|
export const DEFAULT_FONT_SIZE = 24;
|
||||||
|
export const DEFAULT_BUFFER = 3;
|
||||||
|
export const DEFAULT_CUTOFF = 0.25;
|
||||||
|
export const DEFAULT_RADIUS = 8;
|
||||||
|
const MAX_CANVAS_WIDTH = 1024;
|
||||||
|
const BASELINE_SCALE = 0.9;
|
||||||
|
const HEIGHT_SCALE = 1.2;
|
||||||
|
const CACHE_LIMIT = 3;
|
||||||
|
const cache = new LRUCache(CACHE_LIMIT);
|
||||||
|
|
||||||
|
const VALID_PROPS = [
|
||||||
|
'fontFamily',
|
||||||
|
'fontWeight',
|
||||||
|
'characterSet',
|
||||||
|
'fontSize',
|
||||||
|
'sdf',
|
||||||
|
'buffer',
|
||||||
|
'cutoff',
|
||||||
|
'radius'
|
||||||
|
];
|
||||||
|
|
||||||
|
function getDefaultCharacterSet() {
|
||||||
|
const charSet = [];
|
||||||
|
for (let i = 32; i < 128; i++) {
|
||||||
|
charSet.push(String.fromCharCode(i));
|
||||||
|
}
|
||||||
|
return charSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTextStyle(ctx, fontFamily, fontSize, fontWeight) {
|
||||||
|
ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
|
||||||
|
ctx.fillStyle = '#000';
|
||||||
|
ctx.textBaseline = 'baseline';
|
||||||
|
ctx.textAlign = 'left';
|
||||||
|
}
|
||||||
|
function getNewChars(key, characterSet) {
|
||||||
|
const cachedFontAtlas = cache.get(key);
|
||||||
|
if (!cachedFontAtlas) {
|
||||||
|
return characterSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newChars = [];
|
||||||
|
const cachedMapping = cachedFontAtlas.mapping;
|
||||||
|
let cachedCharSet = Object.keys(cachedMapping);
|
||||||
|
cachedCharSet = new Set(cachedCharSet);
|
||||||
|
|
||||||
|
let charSet = characterSet;
|
||||||
|
if (charSet instanceof Array) {
|
||||||
|
charSet = new Set(charSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
charSet.forEach(char => {
|
||||||
|
if (!cachedCharSet.has(char)) {
|
||||||
|
newChars.push(char);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return newChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateAlphaChannel(alphaChannel, imageData) {
|
||||||
|
// populate distance value from tinySDF to image alpha channel
|
||||||
|
for (let i = 0; i < alphaChannel.length; i++) {
|
||||||
|
imageData.data[4 * i + 3] = alphaChannel[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class FontAtlasManager {
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
// font settings
|
||||||
|
this.props = {
|
||||||
|
fontFamily: DEFAULT_FONT_FAMILY,
|
||||||
|
fontWeight: DEFAULT_FONT_WEIGHT,
|
||||||
|
characterSet: DEFAULT_CHAR_SET,
|
||||||
|
fontSize: DEFAULT_FONT_SIZE,
|
||||||
|
buffer: DEFAULT_BUFFER,
|
||||||
|
// sdf only props
|
||||||
|
// https://github.com/mapbox/tiny-sdf
|
||||||
|
sdf: true,
|
||||||
|
cutoff: DEFAULT_CUTOFF,
|
||||||
|
radius: DEFAULT_RADIUS
|
||||||
|
};
|
||||||
|
|
||||||
|
// key is used for caching generated fontAtlas
|
||||||
|
this._key = null;
|
||||||
|
this._texture = new THREE.Texture();
|
||||||
|
}
|
||||||
|
|
||||||
|
get texture() {
|
||||||
|
return this._texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
get mapping() {
|
||||||
|
const data = cache.get(this._key);
|
||||||
|
return data && data.mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
get scale() {
|
||||||
|
return HEIGHT_SCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
get fontAtlas() {
|
||||||
|
return this._fontAtlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
setProps(props = {}) {
|
||||||
|
VALID_PROPS.forEach(prop => {
|
||||||
|
if (prop in props) {
|
||||||
|
this.props[prop] = props[prop];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// update cache key
|
||||||
|
const oldKey = this._key;
|
||||||
|
this._key = this._getKey();
|
||||||
|
|
||||||
|
const charSet = getNewChars(this._key, this.props.characterSet);
|
||||||
|
const cachedFontAtlas = cache.get(this._key);
|
||||||
|
|
||||||
|
// if a fontAtlas associated with the new settings is cached and
|
||||||
|
// there are no new chars
|
||||||
|
if (cachedFontAtlas && charSet.length === 0) {
|
||||||
|
// update texture with cached fontAtlas
|
||||||
|
if (this._key !== oldKey) {
|
||||||
|
this._updateTexture(cachedFontAtlas);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update fontAtlas with new settings
|
||||||
|
const fontAtlas = this._generateFontAtlas(this._key, charSet, cachedFontAtlas);
|
||||||
|
this._fontAtlas = fontAtlas;
|
||||||
|
this._updateTexture(fontAtlas);
|
||||||
|
|
||||||
|
// update cache
|
||||||
|
cache.set(this._key, fontAtlas);
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateTexture({ data: canvas }) {
|
||||||
|
this._texture = new THREE.CanvasTexture(canvas);
|
||||||
|
this._texture.wrapS = THREE.ClampToEdgeWrapping;
|
||||||
|
this._texture.wrapT = THREE.ClampToEdgeWrapping;
|
||||||
|
this._texture.minFilter = THREE.LinearFilter;
|
||||||
|
this._texture.flipY = false;
|
||||||
|
this._texture.needUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_generateFontAtlas(key, characterSet, cachedFontAtlas) {
|
||||||
|
const { fontFamily, fontWeight, fontSize, buffer, sdf, radius, cutoff } = this.props;
|
||||||
|
let canvas = cachedFontAtlas && cachedFontAtlas.data;
|
||||||
|
if (!canvas) {
|
||||||
|
canvas = document.createElement('canvas');
|
||||||
|
canvas.width = MAX_CANVAS_WIDTH;
|
||||||
|
}
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
setTextStyle(ctx, fontFamily, fontSize, fontWeight);
|
||||||
|
|
||||||
|
// 1. build mapping
|
||||||
|
const { mapping, canvasHeight, xOffset, yOffset } = buildMapping(
|
||||||
|
Object.assign(
|
||||||
|
{
|
||||||
|
getFontWidth: char => ctx.measureText(char).width,
|
||||||
|
fontHeight: fontSize * HEIGHT_SCALE,
|
||||||
|
buffer,
|
||||||
|
characterSet,
|
||||||
|
maxCanvasWidth: MAX_CANVAS_WIDTH
|
||||||
|
},
|
||||||
|
cachedFontAtlas && {
|
||||||
|
mapping: cachedFontAtlas.mapping,
|
||||||
|
xOffset: cachedFontAtlas.xOffset,
|
||||||
|
yOffset: cachedFontAtlas.yOffset
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2. update canvas
|
||||||
|
// copy old canvas data to new canvas only when height changed
|
||||||
|
if (canvas.height !== canvasHeight) {
|
||||||
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
canvas.height = canvasHeight;
|
||||||
|
ctx.putImageData(imageData, 0, 0);
|
||||||
|
}
|
||||||
|
setTextStyle(ctx, fontFamily, fontSize, fontWeight);
|
||||||
|
|
||||||
|
// 3. layout characters
|
||||||
|
if (sdf) {
|
||||||
|
const tinySDF = new TinySDF(fontSize, buffer, radius, cutoff, fontFamily, fontWeight);
|
||||||
|
// used to store distance values from tinySDF
|
||||||
|
// tinySDF.size equals `fontSize + buffer * 2`
|
||||||
|
const imageData = ctx.getImageData(0, 0, tinySDF.size, tinySDF.size);
|
||||||
|
|
||||||
|
for (const char of characterSet) {
|
||||||
|
populateAlphaChannel(tinySDF.draw(char), imageData);
|
||||||
|
ctx.putImageData(imageData, mapping[char].x - buffer, mapping[char].y - buffer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const char of characterSet) {
|
||||||
|
ctx.fillText(char, mapping[char].x, mapping[char].y + fontSize * BASELINE_SCALE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
xOffset,
|
||||||
|
yOffset,
|
||||||
|
mapping,
|
||||||
|
data: canvas,
|
||||||
|
width: canvas.width,
|
||||||
|
height: canvas.height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_getKey() {
|
||||||
|
const { fontFamily, fontWeight, fontSize, buffer, sdf, radius, cutoff } = this.props;
|
||||||
|
if (sdf) {
|
||||||
|
return `${fontFamily} ${fontWeight} ${fontSize} ${buffer} ${radius} ${cutoff}`;
|
||||||
|
}
|
||||||
|
return `${fontFamily} ${fontWeight} ${fontSize} ${buffer}`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { buildIconMaping } from '../../util/font-util';
|
||||||
|
import * as THREE from '../../../../core/three';
|
||||||
|
const BUFFER = 3;
|
||||||
|
const MAX_CANVAS_WIDTH = 1024;
|
||||||
|
export default class IconManager {
|
||||||
|
constructor() {
|
||||||
|
this._getIcon = null;
|
||||||
|
this._mapping = {};
|
||||||
|
this._autoPacking = false;
|
||||||
|
this.iconData = {};
|
||||||
|
this._canvas = document.createElement('canvas');
|
||||||
|
this._texture = new THREE.Texture(this._canvas);
|
||||||
|
this.ctx = this._canvas.getContext('2d');
|
||||||
|
}
|
||||||
|
getTexture() {
|
||||||
|
return this._texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateIconAtlas() {
|
||||||
|
this._canvas.width = MAX_CANVAS_WIDTH;
|
||||||
|
this._canvas.height = this._canvasHeigth;
|
||||||
|
for (const key in this.mapping) {
|
||||||
|
const icon = this.mapping[key];
|
||||||
|
const { x, y, image } = icon;
|
||||||
|
this.ctx.drawImage(image, x, y, this.imageWidth, this.imageWidth);
|
||||||
|
}
|
||||||
|
this.texture.magFilter = THREE.LinearFilter;
|
||||||
|
this.texture.minFilter = THREE.LinearFilter;
|
||||||
|
this.texture.needsUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
addImage(id, opt) {
|
||||||
|
this._loadImage(opt).then(image => {
|
||||||
|
this.iconData.push({ id, image });
|
||||||
|
const { mapping, canvasHeight } = buildIconMaping(this.iconData, BUFFER, MAX_CANVAS_WIDTH);
|
||||||
|
this._mapping = mapping;
|
||||||
|
this._canvasHeigth = canvasHeight;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_loadImage(url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const image = new Image();
|
||||||
|
image.onload = () => {
|
||||||
|
resolve(image);
|
||||||
|
};
|
||||||
|
image.onerror = function() {
|
||||||
|
reject(new Error('Could not load image at ' + url));
|
||||||
|
};
|
||||||
|
image.src = url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,8 +8,9 @@ import ColorUtil from '../attr/color-util';
|
||||||
import Controller from './controller/index';
|
import Controller from './controller/index';
|
||||||
import source from './source';
|
import source from './source';
|
||||||
import pickingFragmentShader from '../core/engine/picking/picking_frag.glsl';
|
import pickingFragmentShader from '../core/engine/picking/picking_frag.glsl';
|
||||||
// import PickingMaterial from '../core/engine/picking/pickingMaterial';
|
import { getInteraction } from '../interaction/index';
|
||||||
import Attr from '../attr/index';
|
import Attr from '../attr/index';
|
||||||
|
import diff from '../util/diff';
|
||||||
import Util from '../util';
|
import Util from '../util';
|
||||||
import Global from '../global';
|
import Global from '../global';
|
||||||
let id = 1;
|
let id = 1;
|
||||||
|
@ -36,6 +37,7 @@ export default class Layer extends Base {
|
||||||
attrOptions: {
|
attrOptions: {
|
||||||
},
|
},
|
||||||
scaleOptions: {},
|
scaleOptions: {},
|
||||||
|
preScaleOptions: null,
|
||||||
scales: {},
|
scales: {},
|
||||||
attrs: {},
|
attrs: {},
|
||||||
// 样式配置项
|
// 样式配置项
|
||||||
|
@ -53,6 +55,7 @@ export default class Layer extends Base {
|
||||||
activedOptions: {
|
activedOptions: {
|
||||||
fill: [ 1.0, 0, 0, 1.0 ]
|
fill: [ 1.0, 0, 0, 1.0 ]
|
||||||
},
|
},
|
||||||
|
interactions: {},
|
||||||
animateOptions: {
|
animateOptions: {
|
||||||
enable: false
|
enable: false
|
||||||
}
|
}
|
||||||
|
@ -66,6 +69,7 @@ export default class Layer extends Base {
|
||||||
this._pickObject3D = new THREE.Object3D();
|
this._pickObject3D = new THREE.Object3D();
|
||||||
this._object3D.visible = this.get('visible');
|
this._object3D.visible = this.get('visible');
|
||||||
this._object3D.renderOrder = this.get('zIndex') || 0;
|
this._object3D.renderOrder = this.get('zIndex') || 0;
|
||||||
|
this._mapEventHandlers = [];
|
||||||
const layerId = this._getUniqueId();
|
const layerId = this._getUniqueId();
|
||||||
this.layerId = layerId;
|
this.layerId = layerId;
|
||||||
this._activeIds = null;
|
this._activeIds = null;
|
||||||
|
@ -82,18 +86,15 @@ export default class Layer extends Base {
|
||||||
* @param {*} type mesh类型是区别是填充还是边线
|
* @param {*} type mesh类型是区别是填充还是边线
|
||||||
*/
|
*/
|
||||||
add(object, type = 'fill') {
|
add(object, type = 'fill') {
|
||||||
// composer合图层绘制
|
// composer合图层绘制
|
||||||
if (object.type === 'composer') {
|
if (object.type === 'composer') {
|
||||||
this._object3D = object;
|
this._object3D = object;
|
||||||
this.scene._engine.composerLayers.push(object);
|
this.scene._engine.composerLayers.push(object);
|
||||||
|
setTimeout(() => this.scene._engine.update(), 500);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
type === 'fill' ? this.layerMesh = object : this.layerLineMesh = object;
|
type === 'fill' ? this.layerMesh = object : this.layerLineMesh = object;
|
||||||
this._visibleWithZoom();
|
this._visibleWithZoom();
|
||||||
this._zoomchangeHander = this._visibleWithZoom.bind(this);
|
|
||||||
this.scene.on('zoomchange', this._zoomchangeHander);
|
|
||||||
|
|
||||||
object.onBeforeRender = () => { // 每次渲染前改变状态
|
object.onBeforeRender = () => { // 每次渲染前改变状态
|
||||||
const zoom = this.scene.getZoom();
|
const zoom = this.scene.getZoom();
|
||||||
object.material.setUniformsValue('u_time', this.scene._engine.clock.getElapsedTime());
|
object.material.setUniformsValue('u_time', this.scene._engine.clock.getElapsedTime());
|
||||||
|
@ -104,15 +105,10 @@ export default class Layer extends Base {
|
||||||
object.onAfterRender = () => { // 每次渲染后改变状态
|
object.onAfterRender = () => { // 每次渲染后改变状态
|
||||||
this.afterRender();
|
this.afterRender();
|
||||||
};
|
};
|
||||||
// 更新
|
|
||||||
if (this._needUpdateFilter) { // 动态更新数据过滤
|
|
||||||
this._updateFilter(object);
|
|
||||||
}
|
|
||||||
this._object3D.add(object);
|
this._object3D.add(object);
|
||||||
if (type === 'fill') {
|
if (type === 'fill') {
|
||||||
this._addPickMesh(object);// 不对边界线进行拾取
|
this._addPickMesh(object);// 不对边界线进行拾取
|
||||||
}
|
}
|
||||||
this.scene._engine.update();
|
|
||||||
setTimeout(() => this.scene._engine.update(), 500);
|
setTimeout(() => this.scene._engine.update(), 500);
|
||||||
}
|
}
|
||||||
remove(object) {
|
remove(object) {
|
||||||
|
@ -132,8 +128,13 @@ export default class Layer extends Base {
|
||||||
this._object3D.visible = this.get('visible');
|
this._object3D.visible = this.get('visible');
|
||||||
}
|
}
|
||||||
source(data, cfg = {}) {
|
source(data, cfg = {}) {
|
||||||
|
if (data instanceof source) {
|
||||||
|
this.layerSource = data;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
cfg.data = data;
|
cfg.data = data;
|
||||||
cfg.mapType = this.scene.mapType;
|
cfg.mapType = this.scene.mapType;
|
||||||
|
cfg.zoom = this.scene.getZoom();
|
||||||
this.layerSource = new source(cfg);
|
this.layerSource = new source(cfg);
|
||||||
// this.scene.workerPool.runTask({
|
// this.scene.workerPool.runTask({
|
||||||
// command: 'geojson',
|
// command: 'geojson',
|
||||||
|
@ -144,7 +145,6 @@ export default class Layer extends Base {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
color(field, values) {
|
color(field, values) {
|
||||||
this._needUpdateColor = true;// 标识颜色是否需要更新
|
|
||||||
this._createAttrOption('color', field, values, Global.colors);
|
this._createAttrOption('color', field, values, Global.colors);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,6 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
|
|
||||||
filter(field, values) {
|
filter(field, values) {
|
||||||
this._needUpdateFilter = true;
|
|
||||||
this._createAttrOption('filter', field, values, true);
|
this._createAttrOption('filter', field, values, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -263,6 +262,10 @@ export default class Layer extends Base {
|
||||||
this._visible(true);
|
this._visible(true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
setData(data, cfg) {
|
||||||
|
this.layerSource.setData(data, cfg);
|
||||||
|
this.repaint();
|
||||||
|
}
|
||||||
_createScale(field) {
|
_createScale(field) {
|
||||||
// TODO scale更新
|
// TODO scale更新
|
||||||
const scales = this.get('scales');
|
const scales = this.get('scales');
|
||||||
|
@ -316,25 +319,54 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
return scale;
|
return scale;
|
||||||
}
|
}
|
||||||
|
render() {
|
||||||
|
this.init();
|
||||||
|
this.scene._engine.update();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
// 重绘 度量, 映射,顶点构建
|
||||||
|
repaint() {
|
||||||
|
this.set('scales', {});
|
||||||
|
this._initControllers();
|
||||||
|
this._initAttrs();
|
||||||
|
this._mapping();
|
||||||
|
this.redraw();
|
||||||
|
}
|
||||||
// 初始化图层
|
// 初始化图层
|
||||||
init() {
|
init() {
|
||||||
this._initControllers();
|
this._initControllers();
|
||||||
this._initAttrs();
|
this._initAttrs();
|
||||||
this._scaleByZoom();
|
this._updateDraw();
|
||||||
this._mapping();
|
}
|
||||||
|
_initInteraction() {
|
||||||
const activeHander = this._addActiveFeature.bind(this);
|
|
||||||
const resetHander = this._resetStyle.bind(this);
|
|
||||||
if (this.get('allowActive')) {
|
if (this.get('allowActive')) {
|
||||||
|
this.interaction('active');
|
||||||
this.on('mousemove', activeHander);
|
|
||||||
this.on('mouseleave', resetHander);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.off('mousemove', activeHander);
|
|
||||||
this.off('mouseleave', resetHander);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_initMapEvent() {
|
||||||
|
// zoomchange mapmove resize
|
||||||
|
const EVENT_TYPES = [ 'zoomchange', 'dragend' ];
|
||||||
|
Util.each(EVENT_TYPES, type => {
|
||||||
|
const handler = Util.wrapBehavior(this, `${type}`);
|
||||||
|
this.map.on(`${type}`, handler);
|
||||||
|
this._mapEventHandlers.push({ type, handler });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
clearMapEvent() {
|
||||||
|
const eventHandlers = this._mapEventHandlers;
|
||||||
|
Util.each(eventHandlers, eh => {
|
||||||
|
this.map.off(eh.type, eh.handler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
zoomchange(ev) {
|
||||||
|
// 地图缩放等级变化
|
||||||
|
this._visibleWithZoom(ev);
|
||||||
|
}
|
||||||
|
dragend() {
|
||||||
|
|
||||||
|
}
|
||||||
|
resize() {
|
||||||
|
}
|
||||||
|
|
||||||
setActive(id, color) {
|
setActive(id, color) {
|
||||||
this._activeIds = id;
|
this._activeIds = id;
|
||||||
|
@ -353,6 +385,7 @@ export default class Layer extends Base {
|
||||||
|
|
||||||
|
|
||||||
_initAttrs() {
|
_initAttrs() {
|
||||||
|
// 对比 options变化判断如何更新
|
||||||
const attrOptions = this.get('attrOptions');
|
const attrOptions = this.get('attrOptions');
|
||||||
for (const type in attrOptions) {
|
for (const type in attrOptions) {
|
||||||
if (attrOptions.hasOwnProperty(type)) {
|
if (attrOptions.hasOwnProperty(type)) {
|
||||||
|
@ -360,6 +393,55 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_setPreOption() {
|
||||||
|
const nextAttrs = this.get('attrOptions');
|
||||||
|
const nextStyle = this.get('styleOptions');
|
||||||
|
this.set('preAttrOptions', Util.clone(nextAttrs));
|
||||||
|
this.set('preStyleOption', Util.clone(nextStyle));
|
||||||
|
}
|
||||||
|
_updateDraw() {
|
||||||
|
const preAttrs = this.get('preAttrOptions');
|
||||||
|
const nextAttrs = this.get('attrOptions');
|
||||||
|
const preStyle = this.get('preStyleOption');
|
||||||
|
const nextStyle = this.get('styleOptions');
|
||||||
|
if (preAttrs === undefined && preStyle === undefined) {
|
||||||
|
this._mapping();
|
||||||
|
this._setPreOption();
|
||||||
|
this._scaleByZoom();
|
||||||
|
this._initInteraction();
|
||||||
|
this._initMapEvent();
|
||||||
|
this.draw();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Util.isEqual(preAttrs.color, nextAttrs.color)) {
|
||||||
|
this._updateAttributes(this.layerMesh);
|
||||||
|
}
|
||||||
|
// 更新数据过滤 filter
|
||||||
|
if (!Util.isEqual(preAttrs.filter, nextAttrs.filter)) {
|
||||||
|
// 更新color;
|
||||||
|
this._updateAttributes(this.layerMesh);
|
||||||
|
}
|
||||||
|
// 更新Size
|
||||||
|
if (!Util.isEqual(preAttrs.size, nextAttrs.size)) {
|
||||||
|
// 更新color;
|
||||||
|
this._updateSize();
|
||||||
|
}
|
||||||
|
// 更新形状
|
||||||
|
if (!Util.isEqual(preAttrs.shape, nextAttrs.shape)) {
|
||||||
|
// 更新color;
|
||||||
|
this._updateShape();
|
||||||
|
}
|
||||||
|
if (!Util.isEqual(preStyle, nextStyle)) {
|
||||||
|
// 判断新增,修改,删除
|
||||||
|
const newStyle = {};
|
||||||
|
Util.each(diff(preStyle, nextStyle), ({ type, key, value }) => {
|
||||||
|
(type !== 'remove') && (newStyle[key] = value);
|
||||||
|
// newStyle[key] = type === 'remove' ? null : value;
|
||||||
|
});
|
||||||
|
this._updateStyle(newStyle);
|
||||||
|
}
|
||||||
|
this._setPreOption();
|
||||||
|
}
|
||||||
|
|
||||||
_updateAttr(type) {
|
_updateAttr(type) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
@ -400,7 +482,14 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
this.emit('sizeUpdated', this.zoomSizeCache[zoom]);
|
this.emit('sizeUpdated', this.zoomSizeCache[zoom]);
|
||||||
}
|
}
|
||||||
|
_updateStyle(option) {
|
||||||
|
const newOption = { };
|
||||||
|
for (const key in option) {
|
||||||
|
newOption['u_' + key] = option[key];
|
||||||
|
}
|
||||||
|
this.layerMesh.material.updateUninform(newOption);
|
||||||
|
|
||||||
|
}
|
||||||
_mapping() {
|
_mapping() {
|
||||||
const self = this;
|
const self = this;
|
||||||
const attrs = self.get('attrs');
|
const attrs = self.get('attrs');
|
||||||
|
@ -410,13 +499,12 @@ export default class Layer extends Base {
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
const record = data[i];
|
const record = data[i];
|
||||||
const newRecord = {};
|
const newRecord = {};
|
||||||
|
|
||||||
newRecord.id = data[i]._id;
|
newRecord.id = data[i]._id;
|
||||||
for (const k in attrs) {
|
for (const k in attrs) {
|
||||||
if (attrs.hasOwnProperty(k)) {
|
if (attrs.hasOwnProperty(k)) {
|
||||||
const attr = attrs[k];
|
const attr = attrs[k];
|
||||||
attr.needUpdate = false;
|
|
||||||
const names = attr.names;
|
const names = attr.names;
|
||||||
|
|
||||||
const values = self._getAttrValues(attr, record);
|
const values = self._getAttrValues(attr, record);
|
||||||
if (names.length > 1) { // position 之类的生成多个字段的属性
|
if (names.length > 1) { // position 之类的生成多个字段的属性
|
||||||
for (let j = 0; j < values.length; j++) {
|
for (let j = 0; j < values.length; j++) {
|
||||||
|
@ -433,6 +521,12 @@ export default class Layer extends Base {
|
||||||
newRecord.coordinates = record.coordinates;
|
newRecord.coordinates = record.coordinates;
|
||||||
mappedData.push(newRecord);
|
mappedData.push(newRecord);
|
||||||
}
|
}
|
||||||
|
// 通过透明度过滤数据
|
||||||
|
if (attrs.hasOwnProperty('filter')) {
|
||||||
|
mappedData.forEach(item => {
|
||||||
|
item.filter === false && (item.color[3] = 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
this.layerData = mappedData;
|
this.layerData = mappedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,17 +577,6 @@ export default class Layer extends Base {
|
||||||
const values = attr.mapping(...params);
|
const values = attr.mapping(...params);
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
// temp
|
|
||||||
_getDataType(data) {
|
|
||||||
if (data.hasOwnProperty('type')) {
|
|
||||||
const type = data.type;
|
|
||||||
if (type === 'FeatureCollection') {
|
|
||||||
return 'geojson';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 'basic';
|
|
||||||
}
|
|
||||||
_scaleByZoom() {
|
_scaleByZoom() {
|
||||||
if (this._zoomScale) {
|
if (this._zoomScale) {
|
||||||
this.map.on('zoomend', () => {
|
this.map.on('zoomend', () => {
|
||||||
|
@ -502,11 +585,7 @@ export default class Layer extends Base {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// on(type, callback) {
|
|
||||||
|
|
||||||
// this._addPickingEvents();
|
|
||||||
// super.on(type, callback);
|
|
||||||
// }
|
|
||||||
getPickingId() {
|
getPickingId() {
|
||||||
return this.scene._engine._picking.getNextId();
|
return this.scene._engine._picking.getNextId();
|
||||||
}
|
}
|
||||||
|
@ -519,19 +598,9 @@ export default class Layer extends Base {
|
||||||
_addPickMesh(mesh) {
|
_addPickMesh(mesh) {
|
||||||
this._pickingMesh = new THREE.Object3D();
|
this._pickingMesh = new THREE.Object3D();
|
||||||
this._pickingMesh.name = this.layerId;
|
this._pickingMesh.name = this.layerId;
|
||||||
// this._visibleWithZoom();
|
|
||||||
// this.scene.on('zoomchange', () => {
|
|
||||||
// this._visibleWithZoom();
|
|
||||||
// });
|
|
||||||
this.addToPicking(this._pickingMesh);
|
this.addToPicking(this._pickingMesh);
|
||||||
const pickmaterial = mesh.material.clone();
|
const pickmaterial = mesh.material.clone();
|
||||||
|
|
||||||
pickmaterial.fragmentShader = pickingFragmentShader;
|
pickmaterial.fragmentShader = pickingFragmentShader;
|
||||||
// const pickmaterial = new PickingMaterial({
|
|
||||||
// u_zoom: this.scene.getZoom(),
|
|
||||||
// vs: mesh.material.
|
|
||||||
// });
|
|
||||||
|
|
||||||
const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial);
|
const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial);
|
||||||
pickingMesh.name = this.layerId;
|
pickingMesh.name = this.layerId;
|
||||||
pickmaterial.setDefinesvalue(this.type, true);
|
pickmaterial.setDefinesvalue(this.type, true);
|
||||||
|
@ -542,16 +611,13 @@ export default class Layer extends Base {
|
||||||
this._pickingMesh.add(pickingMesh);
|
this._pickingMesh.add(pickingMesh);
|
||||||
|
|
||||||
}
|
}
|
||||||
_setPickingId() {
|
|
||||||
this._pickingId = this.getPickingId();
|
|
||||||
}
|
|
||||||
_initEvents() {
|
_initEvents() {
|
||||||
this.scene.on('pick-' + this.layerId, e => {
|
this.scene.on('pick-' + this.layerId, e => {
|
||||||
let { featureId, point2d, type } = e;
|
let { featureId, point2d, type } = e;
|
||||||
if (featureId < 0 && this._activeIds !== null) {
|
if (featureId < 0 && this._activeIds !== null) {
|
||||||
type = 'mouseleave';
|
type = 'mouseleave';
|
||||||
// featureId = this._activeIds;
|
|
||||||
}
|
}
|
||||||
|
this._activeIds = featureId;
|
||||||
const feature = this.layerSource.getSelectFeature(featureId);
|
const feature = this.layerSource.getSelectFeature(featureId);
|
||||||
const lnglat = this.scene.containerToLngLat(point2d);
|
const lnglat = this.scene.containerToLngLat(point2d);
|
||||||
const style = this.layerData[featureId - 1];
|
const style = this.layerData[featureId - 1];
|
||||||
|
@ -569,44 +635,11 @@ export default class Layer extends Base {
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 更新active操作
|
|
||||||
* @param {*} featureStyleId 需要更新的要素Id
|
|
||||||
* @param {*} style 更新的要素样式
|
|
||||||
*/
|
|
||||||
updateStyle(featureStyleId, style) {
|
|
||||||
if (this._activeIds) {
|
|
||||||
this._resetStyle();
|
|
||||||
}
|
|
||||||
this._activeIds = featureStyleId;
|
|
||||||
const pickingId = this.layerMesh.geometry.attributes.pickingId.array;
|
|
||||||
const color = style.color;
|
|
||||||
const colorAttr = this.layerMesh.geometry.attributes.a_color;
|
|
||||||
const firstId = pickingId.indexOf(featureStyleId[0]);
|
|
||||||
for (let i = firstId; i < pickingId.length; i++) {
|
|
||||||
if (pickingId[i] === featureStyleId[0]) {
|
|
||||||
colorAttr.array[i * 4 + 0] = color[0];
|
|
||||||
colorAttr.array[i * 4 + 1] = color[1];
|
|
||||||
colorAttr.array[i * 4 + 2] = color[2];
|
|
||||||
colorAttr.array[i * 4 + 3] = color[3];
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
colorAttr.needsUpdate = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateColor() {
|
|
||||||
|
|
||||||
this._updateMaping();
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* 用于过滤数据
|
* 用于过滤数据
|
||||||
* @param {*} object 需要过滤的mesh
|
* @param {*} object 更新颜色和数据过滤
|
||||||
*/
|
*/
|
||||||
_updateFilter(object) {
|
_updateAttributes(object) {
|
||||||
this._updateMaping();
|
this._updateMaping();
|
||||||
const filterData = this.layerData;
|
const filterData = this.layerData;
|
||||||
this._activeIds = null; // 清空选中元素
|
this._activeIds = null; // 清空选中元素
|
||||||
|
@ -642,16 +675,64 @@ export default class Layer extends Base {
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
if (this.type === 'point') {
|
if (this.type === 'point') {
|
||||||
offset = 5;
|
offset = 5;
|
||||||
|
this.shapeType = 'text' && (offset = 10);
|
||||||
|
|
||||||
} else if (this.type === 'polyline') {
|
} else if (this.type === 'polyline') {
|
||||||
offset = 2;
|
offset = 2;
|
||||||
}
|
}
|
||||||
this._object3D.position.z = offset * Math.pow(2, 20 - zoom);
|
this._object3D.position && (this._object3D.position.z = offset * Math.pow(2, 20 - zoom));
|
||||||
if (zoom < minZoom || zoom > maxZoom) {
|
if (zoom < minZoom || zoom > maxZoom) {
|
||||||
this._object3D.visible = false;
|
this._object3D.visible = false;
|
||||||
} else if (this.get('visible')) {
|
} else if (this.get('visible')) {
|
||||||
this._object3D.visible = true;
|
this._object3D.visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重新构建mesh
|
||||||
|
redraw() {
|
||||||
|
this._object3D.children.forEach(child => {
|
||||||
|
this._object3D.remove(child);
|
||||||
|
});
|
||||||
|
this.removeFromPicking(this._pickingMesh);
|
||||||
|
this.draw();
|
||||||
|
}
|
||||||
|
// 更新mesh
|
||||||
|
updateDraw() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// interaction 方法
|
||||||
|
clearAllInteractions() {
|
||||||
|
const interactions = this.get('interactions');
|
||||||
|
Util.each(interactions, (interaction, key) => {
|
||||||
|
interaction.destory();
|
||||||
|
delete interactions[key];
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
clearInteraction(type) {
|
||||||
|
const interactions = this.get('interactions');
|
||||||
|
if (interactions[type]) {
|
||||||
|
interactions[type].destory();
|
||||||
|
delete interactions[type];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
interaction(type, cfg = {}) {
|
||||||
|
cfg.layer = this;
|
||||||
|
const Ctor = getInteraction(type);
|
||||||
|
const interaction = new Ctor(cfg);
|
||||||
|
this._setInteraction(type, interaction);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
_setInteraction(type, interaction) {
|
||||||
|
const interactions = this.get('interactions');
|
||||||
|
if (interactions[type]) {
|
||||||
|
interactions[type].destory();
|
||||||
|
}
|
||||||
|
interactions[type] = interaction;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置高亮要素
|
* 重置高亮要素
|
||||||
*/
|
*/
|
||||||
|
@ -664,6 +745,8 @@ export default class Layer extends Base {
|
||||||
*/
|
*/
|
||||||
destroy() {
|
destroy() {
|
||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
|
this.clearAllInteractions();
|
||||||
|
this.clearMapEvent();
|
||||||
if (this._object3D.type === 'composer') {
|
if (this._object3D.type === 'composer') {
|
||||||
this.remove(this._object3D);
|
this.remove(this._object3D);
|
||||||
|
|
||||||
|
@ -696,7 +779,6 @@ export default class Layer extends Base {
|
||||||
this._object3D = null;
|
this._object3D = null;
|
||||||
this.scene._engine._scene.remove(this._object3D);
|
this.scene._engine._scene.remove(this._object3D);
|
||||||
this.scene._engine._picking.remove(this._pickingMesh);
|
this.scene._engine._picking.remove(this._pickingMesh);
|
||||||
this.scene.off('zoomchange', this._zoomchangeHander);
|
|
||||||
this.destroyed = true;
|
this.destroyed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import FontAtlasManager from '../geom/buffer/point/text/font-manager';
|
||||||
// import { MapProvider } from '../map/AMap';
|
// import { MapProvider } from '../map/AMap';
|
||||||
import { getMap } from '../map/index';
|
import { getMap } from '../map/index';
|
||||||
import Global from '../global';
|
import Global from '../global';
|
||||||
|
import { getInteraction } from '../interaction/index';
|
||||||
import { compileBuiltinModules } from '../geom/shader';
|
import { compileBuiltinModules } from '../geom/shader';
|
||||||
export default class Scene extends Base {
|
export default class Scene extends Base {
|
||||||
getDefaultCfg() {
|
getDefaultCfg() {
|
||||||
|
@ -46,6 +47,12 @@ export default class Scene extends Base {
|
||||||
Map.asyncCamera(this._engine);
|
Map.asyncCamera(this._engine);
|
||||||
this.initLayer();
|
this.initLayer();
|
||||||
this._registEvents();
|
this._registEvents();
|
||||||
|
const hash = this.get('hash');
|
||||||
|
if (hash) {
|
||||||
|
const Ctor = getInteraction('hash');
|
||||||
|
const interaction = new Ctor({ layer: this });
|
||||||
|
interaction._onHashChange();
|
||||||
|
}
|
||||||
this.emit('loaded');
|
this.emit('loaded');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -69,14 +76,6 @@ export default class Scene extends Base {
|
||||||
|
|
||||||
super.off(type, hander);
|
super.off(type, hander);
|
||||||
}
|
}
|
||||||
_initAttribution() {
|
|
||||||
const message = '<a href="http://antv.alipay.com/zh-cn/index.html title="Large-scale WebGL-powered Geospatial Data Visualization">AntV | L7 </a>';
|
|
||||||
const element = document.createElement('div');
|
|
||||||
|
|
||||||
element.innerHTML = message;
|
|
||||||
element.style.cssText += 'position: absolute; pointer-events:none;background: rgba(255, 255, 255, 0.7);font-size: 11px;z-index:100; padding:4px;bottom: 0;right:0px;';
|
|
||||||
this._container.appendChild(element);
|
|
||||||
}
|
|
||||||
addImage() {
|
addImage() {
|
||||||
this.image = new LoadImage();
|
this.image = new LoadImage();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import Base from './base';
|
import Base from './base';
|
||||||
import { getTransform, getParser } from '../source';
|
import { getTransform, getParser } from '../source';
|
||||||
|
import { cluster, formatData } from '../source/transform/cluster';
|
||||||
import { extent, tranfrormCoord } from '../util/geo';
|
import { extent, tranfrormCoord } from '../util/geo';
|
||||||
|
import { clone } from '@antv/util';
|
||||||
import { getMap } from '../map/index';
|
import { getMap } from '../map/index';
|
||||||
export default class Source extends Base {
|
export default class Source extends Base {
|
||||||
getDefaultCfg() {
|
getDefaultCfg() {
|
||||||
|
@ -21,18 +23,40 @@ export default class Source extends Base {
|
||||||
const mapType = this.get('mapType');
|
const mapType = this.get('mapType');
|
||||||
this.projectFlat = getMap(mapType).project;
|
this.projectFlat = getMap(mapType).project;
|
||||||
// 数据解析
|
// 数据解析
|
||||||
|
this._init();
|
||||||
|
|
||||||
|
}
|
||||||
|
_init() {
|
||||||
this._excuteParser();
|
this._excuteParser();
|
||||||
|
const isCluster = this.get('isCluster') || false;
|
||||||
|
isCluster && this._executeCluster();
|
||||||
// 数据转换 统计,聚合,分类
|
// 数据转换 统计,聚合,分类
|
||||||
this._executeTrans();
|
this._executeTrans();
|
||||||
// 坐标转换
|
// 坐标转换
|
||||||
this._projectCoords();
|
this._projectCoords();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
setData(data, cfg = {}) {
|
||||||
|
Object.assign(this._attrs, cfg);
|
||||||
|
const transform = this.get('transforms');
|
||||||
|
this._transforms = transform || [];
|
||||||
|
this.set('data', data);
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
// 数据更新
|
||||||
|
updateTransfrom(cfg) {
|
||||||
|
const { transforms } = cfg;
|
||||||
|
this._transforms = transforms;
|
||||||
|
this.data = clone(this.originData);
|
||||||
|
this._executeTrans();
|
||||||
|
this._projectCoords();
|
||||||
|
}
|
||||||
|
|
||||||
_excuteParser() {
|
_excuteParser() {
|
||||||
const parser = this.get('parser');
|
const parser = this.get('parser');
|
||||||
const { type = 'geojson' } = parser;
|
const { type = 'geojson' } = parser;
|
||||||
const data = this.get('data');
|
const data = this.get('data');
|
||||||
this.data = getParser(type)(data, parser);
|
this.originData = getParser(type)(data, parser);
|
||||||
|
this.data = clone(this.originData);
|
||||||
this.data.extent = extent(this.data.dataArray);
|
this.data.extent = extent(this.data.dataArray);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +75,24 @@ export default class Source extends Base {
|
||||||
const data = getTransform(option.type)(this.data, option);
|
const data = getTransform(option.type)(this.data, option);
|
||||||
Object.assign(this.data, data);
|
Object.assign(this.data, data);
|
||||||
}
|
}
|
||||||
|
_executeCluster() {
|
||||||
|
const clusterCfg = this.get('Cluster') || {};
|
||||||
|
const zoom = this.get('zoom');
|
||||||
|
clusterCfg.zoom = Math.floor(zoom);
|
||||||
|
this.set('cluster', clusterCfg);
|
||||||
|
const clusterData = cluster(this.data, clusterCfg);
|
||||||
|
this.data = clusterData.data;
|
||||||
|
this.pointIndex = clusterData.pointIndex;
|
||||||
|
}
|
||||||
|
updateCusterData(zoom, bbox) {
|
||||||
|
const clusterPoint = this.pointIndex.getClusters(bbox, zoom);
|
||||||
|
this.data.dataArray = formatData(clusterPoint);
|
||||||
|
const clusterCfg = this.get('Cluster') || {};
|
||||||
|
clusterCfg.zoom = Math.floor(zoom);
|
||||||
|
clusterCfg.bbox = bbox;
|
||||||
|
this.set('cluster', clusterCfg);
|
||||||
|
this._projectCoords();
|
||||||
|
}
|
||||||
_projectCoords() {
|
_projectCoords() {
|
||||||
this.data.dataArray.forEach(data => {
|
this.data.dataArray.forEach(data => {
|
||||||
// data.coordinates = this._coordProject(data.coordinates);
|
// data.coordinates = this._coordProject(data.coordinates);
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
export const GeomBase = {
|
||||||
|
color: 'updateDraw',
|
||||||
|
size: 'repaint',
|
||||||
|
filter: 'updateDraw',
|
||||||
|
layer: '',
|
||||||
|
pickable: true,
|
||||||
|
setLayer(layer) {
|
||||||
|
this.layer = layer;
|
||||||
|
this.style = layer.get('styleOption');
|
||||||
|
},
|
||||||
|
getShape(type) {
|
||||||
|
return type;
|
||||||
|
},
|
||||||
|
draw() {
|
||||||
|
const shape = this.getShape();
|
||||||
|
this.Mesh = shape.Mesh();
|
||||||
|
},
|
||||||
|
// 更新geometry buffer;
|
||||||
|
updateDraw() {
|
||||||
|
|
||||||
|
},
|
||||||
|
repaint() {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export const shapeBae = {
|
||||||
|
geometryBuffer() {
|
||||||
|
},
|
||||||
|
|
||||||
|
geometry() {},
|
||||||
|
|
||||||
|
material() {},
|
||||||
|
|
||||||
|
mesh() {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
|
@ -29,12 +29,11 @@ function drawGlyph(layerData, fontAtlasManager) {
|
||||||
const size = element.size;
|
const size = element.size;
|
||||||
const pos = element.coordinates;
|
const pos = element.coordinates;
|
||||||
let text = element.shape || '';
|
let text = element.shape || '';
|
||||||
|
text = text.toString();
|
||||||
const pen = {
|
const pen = {
|
||||||
x: (-text.length * size) / 2,
|
x: (-text.length * size) / 2,
|
||||||
y: 0
|
y: 0
|
||||||
};
|
};
|
||||||
text = text.toString();
|
|
||||||
|
|
||||||
for (let i = 0; i < text.length; i++) {
|
for (let i = 0; i < text.length; i++) {
|
||||||
const metric = mapping[text[i]];
|
const metric = mapping[text[i]];
|
||||||
const { x, y, width, height } = metric;
|
const { x, y, width, height } = metric;
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
const geom = {
|
|
||||||
point: {
|
|
||||||
symbol: [ 'circle', 'hexagon', 'triangle', 'diamond' ],
|
|
||||||
native: {
|
|
||||||
buffer: '',
|
|
||||||
geometry: 'PointGeometry',
|
|
||||||
material: 'PointMaterial'
|
|
||||||
},
|
|
||||||
line: {
|
|
||||||
buffer: 'PointBuffer',
|
|
||||||
geometry: 'PolygonLine',
|
|
||||||
material: 'MeshlineMaterial'
|
|
||||||
},
|
|
||||||
fill: {
|
|
||||||
buffer: 'PointBuffer',
|
|
||||||
geometry: 'PolygonGeometry',
|
|
||||||
material: 'PolygonMaterial'
|
|
||||||
},
|
|
||||||
extrude: {
|
|
||||||
buffer: 'PointBuffer',
|
|
||||||
geometry: 'PolygonGeometry',
|
|
||||||
material: 'PolygonMaterial'
|
|
||||||
},
|
|
||||||
extrudeline: {
|
|
||||||
buffer: 'PointBuffer',
|
|
||||||
geometry: 'PolygonLine',
|
|
||||||
material: 'MeshlineMaterial'
|
|
||||||
},
|
|
||||||
pointGrid: {
|
|
||||||
buffer: 'pointGrid',
|
|
||||||
geometry: 'PolygonLine',
|
|
||||||
material: 'MeshlineMaterial'
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
line: {
|
|
||||||
shape: [ 'native' ]
|
|
||||||
},
|
|
||||||
polygon: {
|
|
||||||
line: {
|
|
||||||
buffer: 'polygonLineBuffer',
|
|
||||||
geometry: 'PolygonLine',
|
|
||||||
material: 'MeshlineMaterial'
|
|
||||||
},
|
|
||||||
fill: {
|
|
||||||
buffer: 'PolygonBuffer',
|
|
||||||
geometry: 'PolygonGeometry',
|
|
||||||
material: 'PolygonMaterial'
|
|
||||||
},
|
|
||||||
extrude: {
|
|
||||||
buffer: 'PolygonBuffer',
|
|
||||||
geometry: 'PolygonGeometry',
|
|
||||||
material: 'PolygonMaterial'
|
|
||||||
},
|
|
||||||
extrudeline: {
|
|
||||||
buffer: 'polygonLineBuffer',
|
|
||||||
geometry: 'PolygonLine',
|
|
||||||
material: 'MeshlineMaterial'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export default geom;
|
|
|
@ -1,35 +1,58 @@
|
||||||
import * as THREE from '../../core/three';
|
import * as THREE from '../../core/three';
|
||||||
import Material from './material';
|
import Material from './material';
|
||||||
import { getModule } from '../../util/shaderModule';
|
import { getModule } from '../../util/shaderModule';
|
||||||
|
export class HeatmapColorizeMaterial extends Material {
|
||||||
|
getDefaultParameters() {
|
||||||
|
return {
|
||||||
|
uniforms: {
|
||||||
|
u_intensity: { value: 1.0 },
|
||||||
|
u_texture: { value: null },
|
||||||
|
u_rampColors: { value: 0 },
|
||||||
|
u_opacity: { value: 1 }
|
||||||
|
},
|
||||||
|
defines: {
|
||||||
|
|
||||||
export function HeatmapIntensityMaterial(opt) {
|
}
|
||||||
const { vs, fs } = getModule('heatmap_intensity');
|
};
|
||||||
const material = new Material({
|
}
|
||||||
uniforms: {
|
constructor(_uniforms, _defines = {}, parameters) {
|
||||||
u_intensity: { value: opt.intensity },
|
super(parameters);
|
||||||
u_radius: { value: opt.radius },
|
const { uniforms, defines } = this.getDefaultParameters();
|
||||||
u_zoom: { value: opt.zoom }
|
const { vs, fs } = getModule('heatmap_color');
|
||||||
},
|
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
|
||||||
vertexShader: vs,
|
this.type = 'HeatmapColorizeMaterial';
|
||||||
fragmentShader: fs,
|
this.defines = Object.assign(defines, _defines);
|
||||||
transparent: true,
|
this.vertexShader = vs;
|
||||||
depthTest: false,
|
this.fragmentShader = fs;
|
||||||
blending: THREE.AdditiveBlending
|
this.transparent = true;
|
||||||
});
|
}
|
||||||
return material;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HeatmapColorizeMaterial(opt) {
|
export class HeatmapIntensityMaterial extends Material {
|
||||||
const { vs, fs } = getModule('heatmap_color');
|
getDefaultParameters() {
|
||||||
const material = new Material({
|
return {
|
||||||
uniforms: {
|
uniforms: {
|
||||||
u_texture: { value: opt.texture },
|
u_intensity: { value: 10.0 },
|
||||||
u_colorRamp: { value: opt.colorRamp },
|
u_zoom: { value: 4 },
|
||||||
u_opacity: { value: opt.opacity }
|
u_radius: { value: 10 }
|
||||||
},
|
},
|
||||||
vertexShader: vs,
|
defines: {
|
||||||
fragmentShader: fs,
|
|
||||||
transparent: true
|
}
|
||||||
});
|
};
|
||||||
return material;
|
}
|
||||||
|
constructor(_uniforms, _defines = {}, parameters) {
|
||||||
|
super(parameters);
|
||||||
|
const { uniforms, defines } = this.getDefaultParameters();
|
||||||
|
const { vs, fs } = getModule('heatmap_intensity');
|
||||||
|
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
|
||||||
|
this.type = 'heatmap_intensity';
|
||||||
|
this.defines = Object.assign(defines, _defines);
|
||||||
|
this.vertexShader = vs;
|
||||||
|
this.blending = THREE.AdditiveBlending;
|
||||||
|
this.fragmentShader = fs;
|
||||||
|
this.depthTest = false;
|
||||||
|
this.transparent = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,8 @@ export function MeshLineMaterial(options) {
|
||||||
},
|
},
|
||||||
vertexShader: vs,
|
vertexShader: vs,
|
||||||
fragmentShader: fs,
|
fragmentShader: fs,
|
||||||
transparent: true
|
transparent: true,
|
||||||
|
blending: THREE.AdditiveBlending
|
||||||
});
|
});
|
||||||
return material;
|
return material;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ export default class Material extends THREE.ShaderMaterial {
|
||||||
}
|
}
|
||||||
return uniforms;
|
return uniforms;
|
||||||
}
|
}
|
||||||
upDateUninform(option) {
|
updateUninform(option) {
|
||||||
for (const key in option) {
|
for (const key in option) {
|
||||||
if (key.substr(0, 2) === 'u_') {
|
if (key.substr(0, 2) === 'u_') {
|
||||||
this.setUniformsValue(key, option[key]);
|
this.setUniformsValue(key, option[key]);
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
uniform sampler2D u_texture;
|
uniform sampler2D u_texture;
|
||||||
uniform sampler2D u_colorRamp;
|
uniform sampler2D u_rampColors;
|
||||||
uniform float u_opacity;
|
uniform float u_opacity;
|
||||||
varying vec2 v_uv;
|
varying vec2 v_uv;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
float intensity = texture2D(u_texture,v_uv).r;
|
float intensity = texture2D(u_texture,v_uv).r;
|
||||||
vec4 color = texture2D(u_colorRamp,vec2(0.5,1.0-intensity));
|
vec4 color = texture2D(u_rampColors,vec2(0.5,1.0-intensity));
|
||||||
gl_FragColor = color;
|
gl_FragColor = color;
|
||||||
gl_FragColor.a = color.a * smoothstep(0.,0.05,intensity) * u_opacity;
|
gl_FragColor.a = color.a * smoothstep(0.,0.05,intensity) * u_opacity;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@ void main() {
|
||||||
}
|
}
|
||||||
#ifdef ANIMATE
|
#ifdef ANIMATE
|
||||||
vTime = 1.0- (mod(u_time*50.,3600.)- position.z) / 100.;
|
vTime = 1.0- (mod(u_time*50.,3600.)- position.z) / 100.;
|
||||||
|
// vTime = 1.0- (28800. + mod(u_time* 10.,28800.)- position.z / 1000.) / 100.;
|
||||||
#endif
|
#endif
|
||||||
gl_Position = matModelViewProjection * vec4(position.xy,0., 1.0);
|
gl_Position = matModelViewProjection * vec4(position.xy, 0., 1.0);
|
||||||
worldId = id_toPickColor(pickingId);
|
worldId = id_toPickColor(pickingId);
|
||||||
}
|
}
|
|
@ -20,7 +20,7 @@ uniform float u_trailLength;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
|
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
|
||||||
vec3 pointPos = position.xyz + vec3(normal * a_size * pow(2.0,20.0-u_zoom) / 2.0 * a_miter);
|
vec3 pointPos = vec3(position.xy,0.) + vec3(normal * a_size * pow(2.0,20.0-u_zoom) / 2.0 * a_miter);
|
||||||
v_color = a_color;
|
v_color = a_color;
|
||||||
if(pickingId == u_activeId) {
|
if(pickingId == u_activeId) {
|
||||||
v_color = u_activeColor;
|
v_color = u_activeColor;
|
||||||
|
@ -30,8 +30,9 @@ void main() {
|
||||||
float alpa =1.0 - fract( mod(1.0- a_distance,u_interval)* (1.0/u_interval) + u_time / u_duration);
|
float alpa =1.0 - fract( mod(1.0- a_distance,u_interval)* (1.0/u_interval) + u_time / u_duration);
|
||||||
alpa = (alpa + u_trailLength -1.0) / u_trailLength;
|
alpa = (alpa + u_trailLength -1.0) / u_trailLength;
|
||||||
vTime = clamp(alpa,0.,1.);
|
vTime = clamp(alpa,0.,1.);
|
||||||
|
// vTime = (28800. + mod(u_time* 1000.,28800.)- position.z) / 100.;
|
||||||
#endif
|
#endif
|
||||||
worldId = id_toPickColor(pickingId);
|
worldId = id_toPickColor(pickingId);
|
||||||
gl_Position = matModelViewProjection * vec4(pointPos, 1.0);
|
gl_Position = matModelViewProjection * vec4(pointPos.xy, 0., 1.0);
|
||||||
|
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@ varying vec4 v_color;
|
||||||
void main() {
|
void main() {
|
||||||
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
|
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
|
||||||
float scale = pow(2.0,(20.0 - u_zoom));
|
float scale = pow(2.0,(20.0 - u_zoom));
|
||||||
vec3 newposition = position + (a_size + vec3(u_strokeWidth/2.,u_strokeWidth/2.,0)) * scale* a_shape;
|
vec3 newposition = position + (a_size + vec3(u_strokeWidth/2.,u_strokeWidth/2.,0)) * scale* a_shape + vec3(0., a_size.y * scale / 4., 0.);;
|
||||||
#ifdef ANIMATE
|
#ifdef ANIMATE
|
||||||
vTime = 1.0- (mod(u_time*50.,3600.)- position.z) / 100.;
|
vTime = 1.0- (mod(u_time*50.,3600.)- position.z) / 100.;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,7 +21,7 @@ void main() {
|
||||||
vec3 newposition = position;
|
vec3 newposition = position;
|
||||||
// newposition.x -= 128.0;
|
// newposition.x -= 128.0;
|
||||||
#ifdef SHAPE
|
#ifdef SHAPE
|
||||||
newposition =position + a_size * scale* a_shape;
|
newposition =position + a_size * scale* a_shape + vec3(0., a_size.y * scale / 4., 0.);
|
||||||
#endif
|
#endif
|
||||||
v_texCoord = faceUv;
|
v_texCoord = faceUv;
|
||||||
if(normal == vec3(0.,0.,1.)){
|
if(normal == vec3(0.,0.,1.)){
|
||||||
|
|
|
@ -7,9 +7,11 @@ uniform float u_buffer;
|
||||||
uniform float u_gamma;
|
uniform float u_gamma;
|
||||||
uniform float u_opacity;
|
uniform float u_opacity;
|
||||||
varying vec2 v_texcoord;
|
varying vec2 v_texcoord;
|
||||||
|
varying float v_size;
|
||||||
void main(){
|
void main(){
|
||||||
float dist=texture2D(u_texture,vec2(v_texcoord.x,v_texcoord.y)).a;
|
float dist=texture2D(u_texture,vec2(v_texcoord.x,v_texcoord.y)).a;
|
||||||
float alpha;
|
float alpha;
|
||||||
|
|
||||||
if(u_strokeWidth==0.){
|
if(u_strokeWidth==0.){
|
||||||
alpha=smoothstep(u_buffer-u_gamma,u_buffer+u_gamma,dist);
|
alpha=smoothstep(u_buffer-u_gamma,u_buffer+u_gamma,dist);
|
||||||
gl_FragColor=vec4(v_color.rgb,alpha*v_color.a);
|
gl_FragColor=vec4(v_color.rgb,alpha*v_color.a);
|
||||||
|
|
|
@ -7,12 +7,14 @@ uniform vec2 u_textTextureSize;// 纹理大小
|
||||||
uniform vec2 u_glSize;
|
uniform vec2 u_glSize;
|
||||||
varying vec2 v_texcoord;
|
varying vec2 v_texcoord;
|
||||||
varying vec4 v_color;
|
varying vec4 v_color;
|
||||||
|
varying float v_size;
|
||||||
uniform float u_activeId;
|
uniform float u_activeId;
|
||||||
uniform vec4 u_activeColor;
|
uniform vec4 u_activeColor;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
mat4 matModelViewProjection=projectionMatrix*modelViewMatrix;
|
mat4 matModelViewProjection=projectionMatrix*modelViewMatrix;
|
||||||
vec4 cur_position=matModelViewProjection*vec4(position.xy,0,1);
|
vec4 cur_position=matModelViewProjection*vec4(position.xy,0,1);
|
||||||
|
v_size = 12. / u_glSize.x;
|
||||||
gl_Position=cur_position/cur_position.w+vec4((a_txtOffsets+a_txtsize)/u_glSize*2.,0.,0.);
|
gl_Position=cur_position/cur_position.w+vec4((a_txtOffsets+a_txtsize)/u_glSize*2.,0.,0.);
|
||||||
v_color=vec4(a_color.rgb,a_color.a*u_opacity);
|
v_color=vec4(a_color.rgb,a_color.a*u_opacity);
|
||||||
if(pickingId==u_activeId){
|
if(pickingId==u_activeId){
|
||||||
|
|
|
@ -1,60 +1,4 @@
|
||||||
import { Vector3 } from '../../core/three';
|
|
||||||
import getNormal from 'polyline-normals';
|
import getNormal from 'polyline-normals';
|
||||||
/**
|
|
||||||
* shape meshLine
|
|
||||||
* @param {array} geo 坐标点
|
|
||||||
* @param {object} props 属性数据
|
|
||||||
* @param {int} index 原始数据ndex
|
|
||||||
* @return {object} 顶点坐标,索引坐标
|
|
||||||
*/
|
|
||||||
export function meshLine(geo, props, index) {
|
|
||||||
const dataLength = geo.length;
|
|
||||||
const width = props.size[0] * 50 || 100;
|
|
||||||
const dem = props.size[1] || 0;
|
|
||||||
const posArray = [];
|
|
||||||
const indexArray = [];
|
|
||||||
const points = [];
|
|
||||||
for (let i = 0; i < dataLength; i++) {
|
|
||||||
let previous = (i === 0) ? geo[0] : geo[i - 1];
|
|
||||||
let next = (i === dataLength - 1) ? geo[dataLength - 1] : geo[i + 1];
|
|
||||||
let current = geo[i];
|
|
||||||
previous = [ previous[0], previous[1], 0 ];
|
|
||||||
next = [ next[0], next[1], 0 ];
|
|
||||||
current = [ current[0], current[1], 0 ];
|
|
||||||
|
|
||||||
let dir = null;
|
|
||||||
if (i === 0 || i === dataLength - 1) {
|
|
||||||
dir = new Vector3(1, 1, 1);
|
|
||||||
} else {
|
|
||||||
const dir1 = new Vector3();
|
|
||||||
const dir2 = new Vector3();
|
|
||||||
dir = new Vector3();
|
|
||||||
dir1.subVectors(new Vector3(...current), new Vector3(...previous)).normalize();
|
|
||||||
dir2.subVectors(new Vector3(...next), new Vector3(...current)).normalize();
|
|
||||||
dir.addVectors(dir1, dir2).normalize();
|
|
||||||
}
|
|
||||||
let normal = [ -dir.y, dir.x, 0 ];
|
|
||||||
normal = [ normal[0] * width, normal[1] * width, 0 ];
|
|
||||||
const n1 = [ normal[0], normal[1], 0 ];
|
|
||||||
const n2 = [ -normal[0], -normal[1], 0 ];
|
|
||||||
const p1 = new Vector3();
|
|
||||||
const p2 = new Vector3();
|
|
||||||
p1.addVectors(new Vector3(...current), new Vector3(...n1));
|
|
||||||
p2.addVectors(new Vector3(...current), new Vector3(...n2));
|
|
||||||
points.push([ p1.x, p1.y, dem ], [ p2.x, p2.y, dem ]);
|
|
||||||
}// end of for
|
|
||||||
for (let i = 0; i < points.length - 2; i += 2) {
|
|
||||||
const ct = i;
|
|
||||||
const cb = i + 1;
|
|
||||||
const nt = i + 2;
|
|
||||||
const nb = i + 3;
|
|
||||||
posArray.push(points[ct], points[cb], points[nt]);
|
|
||||||
posArray.push(points[nt], points[cb], points[nb]);
|
|
||||||
indexArray.push(index, index, index);
|
|
||||||
indexArray.push(index, index, index);
|
|
||||||
}
|
|
||||||
return { positions: posArray, indexes: indexArray };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shape arc
|
* shape arc
|
||||||
|
@ -150,7 +94,7 @@ export function Line(path, props, positionsIndex) {
|
||||||
indexArray[c++] = i + 2;
|
indexArray[c++] = i + 2;
|
||||||
indexArray[c++] = i + 3;
|
indexArray[c++] = i + 3;
|
||||||
}
|
}
|
||||||
point[2] = size[1];
|
// point[2] = size[1];
|
||||||
positions.push(...point);
|
positions.push(...point);
|
||||||
positions.push(...point);
|
positions.push(...point);
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ export function polygonPath(pointCount) {
|
||||||
const step = Math.PI * 2 / pointCount;
|
const step = Math.PI * 2 / pointCount;
|
||||||
const line = [];
|
const line = [];
|
||||||
for (let i = 0; i < pointCount; i++) {
|
for (let i = 0; i < pointCount; i++) {
|
||||||
line.push(step * i);
|
line.push(step * i - Math.PI / 12);
|
||||||
}
|
}
|
||||||
const path = line.map(t => {
|
const path = line.map(t => {
|
||||||
const x = Math.sin(t + Math.PI / 4),
|
const x = Math.sin(t + Math.PI / 4),
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* @author dxq613
|
* @author dxq613
|
||||||
*/
|
*/
|
||||||
// const Global = {};
|
// const Global = {};
|
||||||
|
const FONT_FAMILY = '"-apple-system", BlinkMacSystemFont, "Segoe UI", Roboto,"Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",SimSun, "sans-serif"';
|
||||||
const Global = {
|
const Global = {
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
scene: {
|
scene: {
|
||||||
|
@ -11,24 +12,28 @@ const Global = {
|
||||||
center: [ 107.622, 39.266 ],
|
center: [ 107.622, 39.266 ],
|
||||||
minZoom: 0,
|
minZoom: 0,
|
||||||
maxZoom: 22,
|
maxZoom: 22,
|
||||||
pitch: 0
|
pitch: 0,
|
||||||
|
hash: false
|
||||||
},
|
},
|
||||||
trackable: true,
|
|
||||||
animate: true,
|
animate: true,
|
||||||
snapArray: [ 0, 1, 2, 4, 5, 10 ],
|
|
||||||
height: 0,
|
height: 0,
|
||||||
activeColor: '#2f54eb',
|
activeColor: '#2f54eb',
|
||||||
colors: [ 'rgb(103,0,31)', 'rgb(178,24,43)', 'rgb(214,96,77)', 'rgb(244,165,130)', 'rgb(253,219,199)', 'rgb(247,247,247)', 'rgb(209,229,240)', 'rgb(146,197,222)', 'rgb(67,147,195)', 'rgb(33,102,172)', 'rgb(5,48,97)' ],
|
colors: [ 'rgb(103,0,31)', 'rgb(178,24,43)', 'rgb(214,96,77)', 'rgb(244,165,130)', 'rgb(253,219,199)', 'rgb(247,247,247)', 'rgb(209,229,240)', 'rgb(146,197,222)', 'rgb(67,147,195)', 'rgb(33,102,172)', 'rgb(5,48,97)' ],
|
||||||
// 指定固定 tick 数的逼近值
|
|
||||||
snapCountArray: [ 0, 1, 1.2, 1.5, 1.6, 2, 2.2, 2.4, 2.5, 3, 4, 5, 6, 7.5, 8, 10 ],
|
|
||||||
size: 10000,
|
size: 10000,
|
||||||
shape: 'circle',
|
shape: 'circle',
|
||||||
|
snapArray: [ 0, 1, 2, 4, 5, 10 ],
|
||||||
pointShape: {
|
pointShape: {
|
||||||
'2d': [ 'circle', 'square', 'hexagon', 'triangle' ],
|
'2d': [ 'circle', 'square', 'hexagon', 'triangle' ],
|
||||||
'3d': [ 'cylinder', 'triangleColumn', 'hexagonColumn', 'squareColumn' ]
|
'3d': [ 'cylinder', 'triangleColumn', 'hexagonColumn', 'squareColumn' ]
|
||||||
},
|
},
|
||||||
sdfHomeUrl: 'https://sdf.amap.com',
|
sdfHomeUrl: 'https://sdf.amap.com',
|
||||||
scales: {
|
scales: { },
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
fill: '#ccc',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
fontFamily: FONT_FAMILY,
|
||||||
|
textAlign: 'center'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
13
src/index.js
|
@ -2,10 +2,19 @@
|
||||||
// import Util from './util';
|
// import Util from './util';
|
||||||
import Scene from './core/scene';
|
import Scene from './core/scene';
|
||||||
import Global from './global';
|
import Global from './global';
|
||||||
|
import Source from './core/source';
|
||||||
|
import { registerParser, registerTransform } from './source';
|
||||||
|
import { registerInteraction, getInteraction } from './interaction';
|
||||||
|
import { registerLayer } from './layer';
|
||||||
const version = Global.version;
|
const version = Global.version;
|
||||||
export {
|
export {
|
||||||
version,
|
version,
|
||||||
Scene
|
Scene,
|
||||||
|
Source,
|
||||||
|
registerParser,
|
||||||
|
registerTransform,
|
||||||
|
registerLayer,
|
||||||
|
registerInteraction,
|
||||||
|
getInteraction
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import Interaction from './base';
|
||||||
|
export default class Active extends Interaction {
|
||||||
|
constructor(cfg) {
|
||||||
|
super({
|
||||||
|
processEvent: 'mousemove',
|
||||||
|
resetEvent: 'mouseleave',
|
||||||
|
...cfg
|
||||||
|
});
|
||||||
|
}
|
||||||
|
process(ev) {
|
||||||
|
this.layer._addActiveFeature(ev);
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
this.layer._resetStyle();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
import * as _ from '@antv/util';
|
||||||
|
const EVENT_TYPES = [ 'start', 'process', 'end', 'reset' ];
|
||||||
|
|
||||||
|
export default class Interaction {
|
||||||
|
constructor(cfg) {
|
||||||
|
const defaultCfg = this._getDefaultCfg();
|
||||||
|
Object.assign(this, defaultCfg, cfg);
|
||||||
|
this._eventHandlers = [];
|
||||||
|
this._bindEvents();
|
||||||
|
}
|
||||||
|
_getDefaultCfg() {
|
||||||
|
return {
|
||||||
|
startEvent: 'mousedown',
|
||||||
|
processEvent: 'mousemove',
|
||||||
|
endEvent: 'mouseup',
|
||||||
|
resetEvent: 'dblclick'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_start(ev) {
|
||||||
|
this.preStart(ev);
|
||||||
|
this.start(ev);
|
||||||
|
this.afterStart(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
preStart() {}
|
||||||
|
|
||||||
|
start() {}
|
||||||
|
|
||||||
|
afterStart() {}
|
||||||
|
|
||||||
|
_process(ev) {
|
||||||
|
this.preProcess(ev);
|
||||||
|
this.process(ev);
|
||||||
|
this.afterProcess(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
preProcess() {}
|
||||||
|
|
||||||
|
process() {
|
||||||
|
}
|
||||||
|
|
||||||
|
afterProcess() {}
|
||||||
|
|
||||||
|
_end(ev) {
|
||||||
|
this.preEnd(ev);
|
||||||
|
this.end(ev);
|
||||||
|
this.afterEnd(ev);
|
||||||
|
}
|
||||||
|
preEnd() {}
|
||||||
|
|
||||||
|
end() {}
|
||||||
|
|
||||||
|
afterEnd() {}
|
||||||
|
|
||||||
|
_reset() {
|
||||||
|
this.preReset();
|
||||||
|
this.reset();
|
||||||
|
this.afterReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
preReset() {}
|
||||||
|
|
||||||
|
reset() {}
|
||||||
|
|
||||||
|
afterReset() {}
|
||||||
|
|
||||||
|
_bindEvents() {
|
||||||
|
_.each(EVENT_TYPES, type => {
|
||||||
|
const eventName = this[`${type}Event`];
|
||||||
|
const handler = _.wrapBehavior(this, `_${type}`);
|
||||||
|
this.layer.on(eventName, handler);
|
||||||
|
this._eventHandlers.push({ type: eventName, handler });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_unbindEvents() {
|
||||||
|
const eventHandlers = this._eventHandlers;
|
||||||
|
_.each(eventHandlers, eh => {
|
||||||
|
this.layer.off(eh.type, eh.handler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
destory() {
|
||||||
|
this._unbindEvents();
|
||||||
|
this._reset();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
export const INTERACTION_MAP = {};
|
||||||
|
|
||||||
|
export const getInteraction = type => {
|
||||||
|
return INTERACTION_MAP[type];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerInteraction = (type, ctor) => {
|
||||||
|
// 注册的时候,需要校验 type 重名,不区分大小写
|
||||||
|
if (getInteraction(type)) {
|
||||||
|
throw new Error(`Interaction type '${type}' existed.`);
|
||||||
|
}
|
||||||
|
// 存储到 map 中
|
||||||
|
INTERACTION_MAP[type] = ctor;
|
||||||
|
};
|
|
@ -0,0 +1,58 @@
|
||||||
|
import Interaction from './base';
|
||||||
|
import throttle from '@antv/util/src/throttle.js';
|
||||||
|
export default class Hash extends Interaction {
|
||||||
|
constructor(cfg) {
|
||||||
|
super({
|
||||||
|
endEvent: 'camerachange',
|
||||||
|
...cfg
|
||||||
|
});
|
||||||
|
window.addEventListener('hashchange', this._onHashChange.bind(this), false);
|
||||||
|
this._updateHash = throttle(this._updateHashUnthrottled.bind(this), 20 * 1000 / 100);
|
||||||
|
}
|
||||||
|
end() {
|
||||||
|
this._updateHash();
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
this.layer._resetStyle();
|
||||||
|
}
|
||||||
|
_getHashString() {
|
||||||
|
const center = this.layer.getCenter(),
|
||||||
|
zoom = Math.round(this.layer.getZoom() * 100) / 100,
|
||||||
|
// derived from equation: 512px * 2^z / 360 / 10^d < 0.5px
|
||||||
|
precision = Math.ceil((zoom * Math.LN2 + Math.log(512 / 360 / 0.5)) / Math.LN10),
|
||||||
|
m = Math.pow(10, precision),
|
||||||
|
lng = Math.round(center.lng * m) / m,
|
||||||
|
lat = Math.round(center.lat * m) / m,
|
||||||
|
bearing = this.layer.getRotation(),
|
||||||
|
pitch = this.layer.getPitch();
|
||||||
|
let hash = '';
|
||||||
|
hash += `#${zoom}/${lat}/${lng}`;
|
||||||
|
if (bearing || pitch) hash += (`/${Math.round(bearing * 10) / 10}`);
|
||||||
|
if (pitch) hash += (`/${Math.round(pitch)}`);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
_onHashChange() {
|
||||||
|
const loc = window.location.hash.replace('#', '').split('/');
|
||||||
|
if (loc.length >= 3) {
|
||||||
|
this.layer.setStatus({
|
||||||
|
center: [ +loc[2], +loc[1] ],
|
||||||
|
zoom: +loc[0],
|
||||||
|
bearing: +(loc[3] || 0),
|
||||||
|
pitch: +(loc[4] || 0)
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_updateHashUnthrottled() {
|
||||||
|
const hash = this._getHashString();
|
||||||
|
window.history.replaceState(window.history.state, '', hash);
|
||||||
|
}
|
||||||
|
destory() {
|
||||||
|
window.removeEventListener('hashchange', this._onHashChange, false);
|
||||||
|
this.layer.off('camerachange', this._updateHash);
|
||||||
|
clearTimeout(this._updateHash());
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import Interaction from './base';
|
||||||
|
import Active from './active';
|
||||||
|
import Select from './select';
|
||||||
|
import Hash from './hash';
|
||||||
|
import { getInteraction, registerInteraction } from './factory';
|
||||||
|
|
||||||
|
registerInteraction('active', Active);
|
||||||
|
registerInteraction('select', Select);
|
||||||
|
registerInteraction('hash', Hash);
|
||||||
|
|
||||||
|
export { Interaction, registerInteraction, getInteraction };
|
|
@ -0,0 +1,12 @@
|
||||||
|
import Interaction from './base';
|
||||||
|
export default class Select extends Interaction {
|
||||||
|
constructor(cfg) {
|
||||||
|
super({
|
||||||
|
processEvent: 'click',
|
||||||
|
...cfg
|
||||||
|
});
|
||||||
|
}
|
||||||
|
process(ev) {
|
||||||
|
this.layer._addActiveFeature(ev);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,12 +10,7 @@ export default class HeatMapLayer extends Layer {
|
||||||
this.shapeType = type;
|
this.shapeType = type;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
render() {
|
draw() {
|
||||||
this._prepareRender();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
_prepareRender() {
|
|
||||||
this.init();
|
|
||||||
this.type = 'heatmap';
|
this.type = 'heatmap';
|
||||||
switch (this.shapeType) {
|
switch (this.shapeType) {
|
||||||
case 'grid' :
|
case 'grid' :
|
||||||
|
@ -56,10 +51,4 @@ export default class HeatMapLayer extends Layer {
|
||||||
this.add(girdMesh);
|
this.add(girdMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// afterRender() {
|
|
||||||
// if (this.shapeType !== 'grid' && this.shapeType !== 'hexagon') {
|
|
||||||
// updateIntensityPass(this);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,7 @@ import ImageBuffer from '../geom/buffer/image';
|
||||||
// import ImageGeometry from '../geom/bufferGeometry/image';
|
// import ImageGeometry from '../geom/bufferGeometry/image';
|
||||||
import ImageMaterial from '../geom/material/imageMaterial';
|
import ImageMaterial from '../geom/material/imageMaterial';
|
||||||
export default class imageLayer extends Layer {
|
export default class imageLayer extends Layer {
|
||||||
render() {
|
draw() {
|
||||||
this.init();
|
|
||||||
this.type = 'image';
|
this.type = 'image';
|
||||||
const source = this.layerSource;
|
const source = this.layerSource;
|
||||||
const { opacity } = this.get('styleOptions');
|
const { opacity } = this.get('styleOptions');
|
||||||
|
|
|
@ -14,4 +14,5 @@ registerLayer('RasterLayer', RasterLayer);
|
||||||
registerLayer('HeatmapLayer', HeatmapLayer);
|
registerLayer('HeatmapLayer', HeatmapLayer);
|
||||||
|
|
||||||
export { LAYER_MAP } from './factory';
|
export { LAYER_MAP } from './factory';
|
||||||
|
export { registerLayer };
|
||||||
|
|
||||||
|
|
|
@ -1,112 +1,45 @@
|
||||||
import Layer from '../core/layer';
|
import Layer from '../core/layer';
|
||||||
import * as THREE from '../core/three';
|
import DrawLine from './render/line/drawMeshLine';
|
||||||
|
import DrawArc from './render/line/drawArc';
|
||||||
import { LineBuffer } from '../geom/buffer/index';
|
import { LineBuffer } from '../geom/buffer/index';
|
||||||
import { LineMaterial, ArcLineMaterial, MeshLineMaterial, DashLineMaterial } from '../geom/material/lineMaterial';
|
|
||||||
export default class LineLayer extends Layer {
|
export default class LineLayer extends Layer {
|
||||||
shape(type) {
|
shape(type) {
|
||||||
this.shapeType = type;
|
this.shapeType = type;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
render() {
|
|
||||||
this.type = 'polyline';
|
|
||||||
this.init();
|
|
||||||
const layerData = this.layerData;
|
|
||||||
const style = this.get('styleOptions');
|
|
||||||
const buffer = this._buffer = new LineBuffer({
|
|
||||||
layerData,
|
|
||||||
shapeType: this.shapeType,
|
|
||||||
style
|
|
||||||
});
|
|
||||||
const { opacity } = this.get('styleOptions');
|
|
||||||
const animateOptions = this.get('animateOptions');
|
|
||||||
const activeOption = this.get('activedOptions');
|
|
||||||
const geometry = new THREE.BufferGeometry();
|
|
||||||
const { attributes } = buffer;
|
|
||||||
|
|
||||||
if (this.shapeType === 'arc') {
|
|
||||||
geometry.setIndex(attributes.indexArray);
|
|
||||||
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
|
|
||||||
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
|
|
||||||
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
|
|
||||||
geometry.addAttribute('a_instance', new THREE.Float32BufferAttribute(attributes.instances, 4));
|
|
||||||
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
|
|
||||||
const material = new ArcLineMaterial({
|
|
||||||
u_opacity: opacity,
|
|
||||||
u_zoom: this.scene.getZoom(),
|
|
||||||
activeColor: activeOption.fill
|
|
||||||
});
|
|
||||||
const mesh = new THREE.Mesh(geometry, material);
|
|
||||||
this.add(mesh);
|
|
||||||
} else if (this.shapeType === 'line') {
|
|
||||||
|
|
||||||
geometry.setIndex(attributes.indexArray);
|
|
||||||
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
|
|
||||||
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
|
|
||||||
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
|
|
||||||
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
|
|
||||||
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normal, 3));
|
|
||||||
geometry.addAttribute('a_miter', new THREE.Float32BufferAttribute(attributes.miter, 1));
|
|
||||||
geometry.addAttribute('a_distance', new THREE.Float32BufferAttribute(attributes.attrDistance, 1));
|
|
||||||
const lineType = style.lineType;
|
|
||||||
let material;
|
|
||||||
|
|
||||||
if (lineType !== 'dash') {
|
|
||||||
|
|
||||||
material = new MeshLineMaterial({
|
|
||||||
u_opacity: opacity,
|
|
||||||
u_zoom: this.scene.getZoom(),
|
|
||||||
activeColor: activeOption.fill
|
|
||||||
});
|
|
||||||
|
|
||||||
if (animateOptions.enable) {
|
|
||||||
|
|
||||||
material.setDefinesvalue('ANIMATE', true);
|
|
||||||
this.scene.startAnimate();
|
|
||||||
const { duration, interval, trailLength, repeat = Infinity } = animateOptions;
|
|
||||||
this.animateDuration = this.scene._engine.clock.getElapsedTime() + duration * repeat;
|
|
||||||
material.upDateUninform({
|
|
||||||
u_duration: duration,
|
|
||||||
u_interval: interval,
|
|
||||||
u_trailLength: trailLength
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
geometry.addAttribute('a_distance', new THREE.Float32BufferAttribute(attributes.attrDistance, 1));
|
|
||||||
material = new DashLineMaterial({
|
|
||||||
u_opacity: opacity,
|
|
||||||
u_zoom: this.scene.getZoom(),
|
|
||||||
activeColor: activeOption.fill
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const mesh = new THREE.Mesh(geometry, material);
|
|
||||||
this.add(mesh);
|
|
||||||
} else { // 直线
|
|
||||||
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
|
|
||||||
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
|
|
||||||
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
|
|
||||||
const material = new LineMaterial({
|
|
||||||
u_opacity: opacity,
|
|
||||||
u_time: 0,
|
|
||||||
activeColor: activeOption.fill
|
|
||||||
});
|
|
||||||
if (animateOptions.enable) {
|
|
||||||
material.setDefinesvalue('ANIMATE', true);
|
|
||||||
this.scene.startAnimate();
|
|
||||||
}
|
|
||||||
|
|
||||||
const mesh = new THREE.LineSegments(geometry, material);
|
|
||||||
this.add(mesh);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
preRender() {
|
preRender() {
|
||||||
if (this.animateDuration > 0 && this.animateDuration < this.scene._engine.clock.getElapsedTime()) {
|
if (
|
||||||
|
this.animateDuration > 0 &&
|
||||||
|
this.animateDuration < this.scene._engine.clock.getElapsedTime()
|
||||||
|
) {
|
||||||
this.layerMesh.material.setDefinesvalue('ANIMATE', false);
|
this.layerMesh.material.setDefinesvalue('ANIMATE', false);
|
||||||
this.emit('animateEnd');
|
this.emit('animateEnd');
|
||||||
this.scene.stopAnimate();
|
this.scene.stopAnimate();
|
||||||
this.animateDuration = Infinity;
|
this.animateDuration = Infinity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
draw() {
|
||||||
|
this.type = 'polyline';
|
||||||
|
const layerData = this.layerData;
|
||||||
|
const style = this.get('styleOptions');
|
||||||
|
const animateOptions = this.get('animateOptions');
|
||||||
|
const activeOption = this.get('activedOptions');
|
||||||
|
const layerCfg = {
|
||||||
|
zoom: this.scene.getZoom(),
|
||||||
|
style,
|
||||||
|
animateOptions,
|
||||||
|
activeOption
|
||||||
|
};
|
||||||
|
const buffer = (this._buffer = new LineBuffer({
|
||||||
|
layerData,
|
||||||
|
shapeType: this.shapeType,
|
||||||
|
style
|
||||||
|
}));
|
||||||
|
const { attributes } = buffer;
|
||||||
|
if (this.shapeType === 'arc') {
|
||||||
|
DrawArc(attributes, layerCfg, this);
|
||||||
|
} else {
|
||||||
|
DrawLine(attributes, layerCfg, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,21 +14,8 @@ const { pointShape } = Global;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class PointLayer extends Layer {
|
export default class PointLayer extends Layer {
|
||||||
render() {
|
draw() {
|
||||||
this.type = 'point';
|
this.type = 'point';
|
||||||
this.init();
|
|
||||||
if (!this._hasRender) {
|
|
||||||
this._prepareRender(this.shapeType);
|
|
||||||
this._hasRender = true;
|
|
||||||
} else {
|
|
||||||
this._initAttrs();
|
|
||||||
this._needUpdateFilter || this._needUpdateColor
|
|
||||||
? this._updateFilter()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
_prepareRender() {
|
|
||||||
const { stroke, fill } = this.get('styleOptions');
|
const { stroke, fill } = this.get('styleOptions');
|
||||||
const style = this.get('styleOptions');
|
const style = this.get('styleOptions');
|
||||||
const activeOption = this.get('activedOptions');
|
const activeOption = this.get('activedOptions');
|
||||||
|
@ -37,6 +24,7 @@ export default class PointLayer extends Layer {
|
||||||
activeColor: activeOption.fill
|
activeColor: activeOption.fill
|
||||||
};
|
};
|
||||||
const pointShapeType = this._getShape();
|
const pointShapeType = this._getShape();
|
||||||
|
this.shapeType = pointShapeType;
|
||||||
switch (pointShapeType) {
|
switch (pointShapeType) {
|
||||||
case 'fill': { // 填充图形
|
case 'fill': { // 填充图形
|
||||||
if (fill !== 'none') {
|
if (fill !== 'none') {
|
||||||
|
@ -112,4 +100,33 @@ export default class PointLayer extends Layer {
|
||||||
}
|
}
|
||||||
return 'text';
|
return 'text';
|
||||||
}
|
}
|
||||||
|
zoomchange(ev) {
|
||||||
|
super.zoomchange(ev);
|
||||||
|
this._updateData();
|
||||||
|
}
|
||||||
|
dragend(ev) {
|
||||||
|
super.dragend(ev);
|
||||||
|
this._updateData();
|
||||||
|
|
||||||
|
}
|
||||||
|
_updateData() {
|
||||||
|
if (this.layerSource.get('isCluster')) {
|
||||||
|
const bounds = this.scene.getBounds().toBounds();
|
||||||
|
const SW = bounds.getSouthWest();
|
||||||
|
const NE = bounds.getNorthEast();
|
||||||
|
const zoom = this.scene.getZoom();
|
||||||
|
const step = Math.max(NE.lng - SW.lng, NE.lat - SW.lat) / 2;
|
||||||
|
const bbox = [ SW.lng, SW.lat, NE.lng, NE.lat ];
|
||||||
|
// const bbox = [ SW.lng - step, SW.lat - step, NE.lng + step, NE.lat + step ];
|
||||||
|
const cfg = this.layerSource.get('cluster');
|
||||||
|
const preBox = cfg.bbox;
|
||||||
|
const preZoom = cfg.zoom;
|
||||||
|
if (!(preBox && preBox[0] < bbox[0] && preBox[1] < bbox[1] && preBox[2] > bbox[2] && preBox[3] < bbox[3] && // 当前范围在范围内
|
||||||
|
(Math.abs(zoom - preZoom)) < 0.5)) {
|
||||||
|
const newbbox = [ SW.lng - step, SW.lat - step, NE.lng + step, NE.lat + step ];
|
||||||
|
this.layerSource.updateCusterData(Math.floor(zoom - 1), newbbox);
|
||||||
|
this.repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,7 @@ export default class PolygonLayer extends Layer {
|
||||||
this.shape = type;
|
this.shape = type;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
render() {
|
draw() {
|
||||||
if (!this._hasRender) { // 首次渲染
|
|
||||||
this._hasRender = true;
|
|
||||||
this._prepareRender();
|
|
||||||
} else {
|
|
||||||
|
|
||||||
this._initAttrs();
|
|
||||||
(this._needUpdateFilter || this._needUpdateColor) ? this._updateFilter(this.layerMesh) : null;
|
|
||||||
// TODO update Style;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
_prepareRender() {
|
|
||||||
this.init();
|
this.init();
|
||||||
this.type = 'polygon';
|
this.type = 'polygon';
|
||||||
this._buffer = new PolygonBuffer({
|
this._buffer = new PolygonBuffer({
|
||||||
|
@ -29,7 +17,6 @@ export default class PolygonLayer extends Layer {
|
||||||
}
|
}
|
||||||
update() {
|
update() {
|
||||||
this.updateFilter(this.layerMesh);
|
this.updateFilter(this.layerMesh);
|
||||||
// 动态更新相关属性
|
|
||||||
}
|
}
|
||||||
_getLayerRender() {
|
_getLayerRender() {
|
||||||
const animateOptions = this.get('animateOptions');
|
const animateOptions = this.get('animateOptions');
|
||||||
|
|
|
@ -5,9 +5,8 @@ import { RasterBuffer } from '../geom/buffer/raster';
|
||||||
|
|
||||||
export default class RasterLayer extends Layer {
|
export default class RasterLayer extends Layer {
|
||||||
|
|
||||||
render() {
|
draw() {
|
||||||
this.type = 'raster';
|
this.type = 'raster';
|
||||||
this.init();
|
|
||||||
const source = this.layerSource;
|
const source = this.layerSource;
|
||||||
// 加载 完成事件
|
// 加载 完成事件
|
||||||
const styleOptions = this.get('styleOptions');
|
const styleOptions = this.get('styleOptions');
|
||||||
|
|
|
@ -10,7 +10,8 @@ import * as THREE from '../../../core/three';
|
||||||
export function drawHeatmap(layer) {
|
export function drawHeatmap(layer) {
|
||||||
|
|
||||||
const colors = layer.get('styleOptions').rampColors;
|
const colors = layer.get('styleOptions').rampColors;
|
||||||
layer.colorRamp = createColorRamp(colors);
|
|
||||||
|
layer.rampColors = createColorRamp(colors);
|
||||||
const heatmap = new heatmapPass(layer);
|
const heatmap = new heatmapPass(layer);
|
||||||
const copy = new copyPass(layer);
|
const copy = new copyPass(layer);
|
||||||
copy.renderToScreen = true;
|
copy.renderToScreen = true;
|
||||||
|
@ -18,31 +19,42 @@ export function drawHeatmap(layer) {
|
||||||
composer.addPass(heatmap);
|
composer.addPass(heatmap);
|
||||||
composer.addPass(copy);
|
composer.addPass(copy);
|
||||||
layer.add(composer);
|
layer.add(composer);
|
||||||
|
layer.scene._engine.update();
|
||||||
|
layer._updateStyle = style => {
|
||||||
|
if (style.rampColors) {
|
||||||
|
style.rampColors = createColorRamp(style.rampColors);
|
||||||
|
}
|
||||||
|
const newOption = { };
|
||||||
|
for (const key in style) {
|
||||||
|
newOption['u_' + key] = style[key];
|
||||||
|
}
|
||||||
|
heatmap.scene.children[0].material.updateUninform(newOption);
|
||||||
|
copy.scene.children[0].material.updateUninform(newOption);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function heatmapPass(layer) {
|
function heatmapPass(layer) {
|
||||||
const scene = new THREE.Scene();
|
const scene = new THREE.Scene();
|
||||||
const style = layer.get('styleOptions');
|
const style = layer.get('styleOptions');
|
||||||
const data = layer.layerData;
|
const data = layer.layerData;
|
||||||
const camera = layer.scene._engine._camera;
|
const camera = layer.scene._engine._camera;
|
||||||
// get attributes data
|
// get attributes data
|
||||||
const buffer = new HeatmapBuffer({
|
const buffer = new HeatmapBuffer({
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
const attributes = buffer.attributes;
|
const attributes = buffer.attributes;
|
||||||
// create geometery
|
// create geometery
|
||||||
const geometry = new THREE.BufferGeometry();
|
const geometry = new THREE.BufferGeometry();
|
||||||
// geometry.setIndex(attributes.indices);
|
// geometry.setIndex(attributes.indices);
|
||||||
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
|
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
|
||||||
geometry.addAttribute('a_dir', new THREE.Float32BufferAttribute(attributes.dirs, 2));
|
geometry.addAttribute('a_dir', new THREE.Float32BufferAttribute(attributes.dirs, 2));
|
||||||
geometry.addAttribute('a_weight', new THREE.Float32BufferAttribute(attributes.weights, 1));
|
geometry.addAttribute('a_weight', new THREE.Float32BufferAttribute(attributes.weights, 1));
|
||||||
const material = new HeatmapIntensityMaterial({
|
const material = new HeatmapIntensityMaterial({
|
||||||
intensity: style.intensity,
|
u_intensity: style.intensity,
|
||||||
radius: style.radius,
|
u_radius: style.radius,
|
||||||
zoom: layer.scene.getZoom()
|
u_zoom: layer.scene.getZoom()
|
||||||
});
|
}, {});
|
||||||
const mesh = new THREE.Mesh(geometry, material);
|
const mesh = new THREE.Mesh(geometry, material);
|
||||||
scene.add(mesh);
|
scene.add(mesh);
|
||||||
scene.onBeforeRender = () => { // 每次渲染前改变状态
|
scene.onBeforeRender = () => { // 每次渲染前改变状态
|
||||||
|
@ -55,9 +67,9 @@ function heatmapPass(layer) {
|
||||||
function copyPass(layer) {
|
function copyPass(layer) {
|
||||||
const style = layer.get('styleOptions');
|
const style = layer.get('styleOptions');
|
||||||
const material = new HeatmapColorizeMaterial({
|
const material = new HeatmapColorizeMaterial({
|
||||||
colorRamp: layer.colorRamp,
|
u_rampColors: layer.rampColors,
|
||||||
opacity: style.opacity
|
u_opacity: style.opacity
|
||||||
});
|
}, {});
|
||||||
const copyPass = new ShaderPass(material, 'u_texture');
|
const copyPass = new ShaderPass(material, 'u_texture');
|
||||||
return copyPass;
|
return copyPass;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import * as THREE from '../../../core/three';
|
import * as THREE from '../../../core/three';
|
||||||
import { ArcLineMaterial } from '../../../geom/material/lineMaterial';
|
import { ArcLineMaterial } from '../../../geom/material/lineMaterial';
|
||||||
export default function DrawArcLine(attributes, style) {
|
export default function DrawArcLine(attributes, cfg, layer) {
|
||||||
|
const { style, activeOption } = cfg;
|
||||||
const { opacity, zoom } = style;
|
const { opacity, zoom } = style;
|
||||||
const geometry = new THREE.BufferGeometry();
|
const geometry = new THREE.BufferGeometry();
|
||||||
geometry.setIndex(attributes.indexArray);
|
geometry.setIndex(attributes.indexArray);
|
||||||
|
@ -10,10 +11,11 @@ export default function DrawArcLine(attributes, style) {
|
||||||
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
|
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
|
||||||
const lineMaterial = new ArcLineMaterial({
|
const lineMaterial = new ArcLineMaterial({
|
||||||
u_opacity: opacity,
|
u_opacity: opacity,
|
||||||
u_zoom: zoom
|
u_zoom: zoom,
|
||||||
|
activeColor: activeOption.fill
|
||||||
}, {
|
}, {
|
||||||
SHAPE: false
|
SHAPE: false
|
||||||
});
|
});
|
||||||
const arcMesh = new THREE.Mesh(geometry, lineMaterial);
|
const arcMesh = new THREE.Mesh(geometry, lineMaterial);
|
||||||
return arcMesh;
|
layer.add(arcMesh);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as THREE from '../../../core/three';
|
import * as THREE from '../../../core/three';
|
||||||
import { MeshLineMaterial } from '../../../geom/material/lineMaterial';
|
import { MeshLineMaterial } from '../../../geom/material/lineMaterial';
|
||||||
export default function DrawLine(attributes, style) {
|
export default function DrawLine(attributes, cfg, layer) {
|
||||||
const { opacity, zoom, animate, duration, interval, trailLength } = style;
|
const { style, animateOptions, activeOption, zoom } = cfg;
|
||||||
const geometry = new THREE.BufferGeometry();
|
const geometry = new THREE.BufferGeometry();
|
||||||
geometry.setIndex(attributes.indexArray);
|
geometry.setIndex(attributes.indexArray);
|
||||||
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
|
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
|
||||||
|
@ -11,17 +11,34 @@ export default function DrawLine(attributes, style) {
|
||||||
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normal, 3));
|
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normal, 3));
|
||||||
geometry.addAttribute('a_miter', new THREE.Float32BufferAttribute(attributes.miter, 1));
|
geometry.addAttribute('a_miter', new THREE.Float32BufferAttribute(attributes.miter, 1));
|
||||||
geometry.addAttribute('a_distance', new THREE.Float32BufferAttribute(attributes.attrDistance, 1));
|
geometry.addAttribute('a_distance', new THREE.Float32BufferAttribute(attributes.attrDistance, 1));
|
||||||
|
|
||||||
const lineMaterial = new MeshLineMaterial({
|
const lineMaterial = new MeshLineMaterial({
|
||||||
u_opacity: opacity,
|
u_opacity: style.opacity,
|
||||||
u_zoom: zoom,
|
u_zoom: zoom,
|
||||||
u_duration: duration,
|
u_time: 0,
|
||||||
u_interval: interval,
|
activeColor: activeOption.fill
|
||||||
u_trailLength: trailLength,
|
|
||||||
u_time: 0
|
|
||||||
}, {
|
}, {
|
||||||
SHAPE: false,
|
SHAPE: false,
|
||||||
ANIMATE: animate
|
ANIMATE: false
|
||||||
});
|
});
|
||||||
const arcMesh = new THREE.Mesh(geometry, lineMaterial);
|
|
||||||
return arcMesh;
|
const lineMesh = new THREE.Mesh(geometry, lineMaterial);
|
||||||
|
if (animateOptions.enable) {
|
||||||
|
layer.scene.startAnimate();
|
||||||
|
const {
|
||||||
|
duration = 2,
|
||||||
|
interval = 0.5,
|
||||||
|
trailLength = 0.5,
|
||||||
|
repeat = Infinity
|
||||||
|
} = animateOptions;
|
||||||
|
layer.animateDuration =
|
||||||
|
layer.scene._engine.clock.getElapsedTime() + duration * repeat;
|
||||||
|
lineMaterial.updateUninform({
|
||||||
|
u_duration: duration,
|
||||||
|
u_interval: interval,
|
||||||
|
u_trailLength: trailLength
|
||||||
|
});
|
||||||
|
lineMaterial.setDefinesvalue('ANIMATE', true);
|
||||||
|
}
|
||||||
|
layer.add(lineMesh);
|
||||||
}
|
}
|
|
@ -37,7 +37,7 @@ export default function DrawText(attributes, style) {
|
||||||
attributes.fontAtlas.width,
|
attributes.fontAtlas.width,
|
||||||
attributes.fontAtlas.height
|
attributes.fontAtlas.height
|
||||||
],
|
],
|
||||||
u_gamma: 0.2,
|
u_gamma: (1.0 / 12.0) * (1.4142135623730951 / (2.0)),
|
||||||
u_buffer: 0.75,
|
u_buffer: 0.75,
|
||||||
u_opacity: opacity,
|
u_opacity: opacity,
|
||||||
u_glSize: [ width, height ],
|
u_glSize: [ width, height ],
|
||||||
|
|
|
@ -25,7 +25,7 @@ export default function DrawAnimate(attributes, style) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawAnimate.prototype.updateStyle = function(style) {
|
DrawAnimate.prototype.updateStyle = function(style) {
|
||||||
this.fillPolygonMesh.material.upDateUninform({
|
this.fillPolygonMesh.material.updateUninform({
|
||||||
u_opacity: style.opacity,
|
u_opacity: style.opacity,
|
||||||
u_baseColor: style.baseColor,
|
u_baseColor: style.baseColor,
|
||||||
u_brightColor: style.brightColor,
|
u_brightColor: style.brightColor,
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
// import * as THREE from '../../core/three';
|
||||||
|
// import Tile from './tile';
|
||||||
|
// export default class ImageTile extends Tile {
|
||||||
|
// constructor(layer, z, x, y) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// requestTileAsync() {
|
||||||
|
// // Making this asynchronous really speeds up the LOD framerate
|
||||||
|
// setTimeout(() => {
|
||||||
|
// if (!this._mesh) {
|
||||||
|
// this._mesh = this._createMesh();
|
||||||
|
// this._requestTile();
|
||||||
|
// }
|
||||||
|
// }, 0);
|
||||||
|
// }
|
||||||
|
// _requestTile() {
|
||||||
|
// const urlParams = {
|
||||||
|
// x: this._tile[0],
|
||||||
|
// y: this._tile[1],
|
||||||
|
// z: this._tile[2]
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const url = this._getTileURL(urlParams);
|
||||||
|
|
||||||
|
// const image = document.createElement('img');
|
||||||
|
|
||||||
|
// image.addEventListener('load', event => {
|
||||||
|
// const texture = new THREE.Texture();
|
||||||
|
|
||||||
|
// texture.image = image;
|
||||||
|
// texture.needsUpdate = true;
|
||||||
|
|
||||||
|
// // Silky smooth images when tilted
|
||||||
|
// texture.magFilter = THREE.LinearFilter;
|
||||||
|
// texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||||
|
|
||||||
|
// // TODO: Set this to renderer.getMaxAnisotropy() / 4
|
||||||
|
// texture.anisotropy = 4;
|
||||||
|
|
||||||
|
// texture.needsUpdate = true;
|
||||||
|
|
||||||
|
// // Something went wrong and the tile or its material is missing
|
||||||
|
// //
|
||||||
|
// // Possibly removed by the cache before the image loaded
|
||||||
|
// if (!this._mesh || !this._mesh.children[0] || !this._mesh.children[0].material) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// this._mesh.children[0].material.map = texture;
|
||||||
|
// this._mesh.children[0].material.needsUpdate = true;
|
||||||
|
|
||||||
|
// this._texture = texture;
|
||||||
|
// this._ready = true;
|
||||||
|
// }, false);
|
||||||
|
|
||||||
|
// // image.addEventListener('progress', event => {}, false);
|
||||||
|
// // image.addEventListener('error', event => {}, false);
|
||||||
|
|
||||||
|
// image.crossOrigin = '';
|
||||||
|
|
||||||
|
// // Load image
|
||||||
|
// image.src = url;
|
||||||
|
|
||||||
|
// this._image = image;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// _createMesh() {
|
||||||
|
// // Something went wrong and the tile
|
||||||
|
// //
|
||||||
|
// // Possibly removed by the cache before loaded
|
||||||
|
// if (!this._center) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const mesh = new THREE.Object3D();
|
||||||
|
// const geom = new THREE.PlaneBufferGeometry(this._side, this._side, 1);
|
||||||
|
|
||||||
|
// let material;
|
||||||
|
// if (!this._world._environment._skybox) {
|
||||||
|
// material = new THREE.MeshBasicMaterial({
|
||||||
|
// depthWrite: false
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // const material = new THREE.MeshPhongMaterial({
|
||||||
|
// // depthWrite: false
|
||||||
|
// // });
|
||||||
|
// } else {
|
||||||
|
// // Other MeshStandardMaterial settings
|
||||||
|
// //
|
||||||
|
// // material.envMapIntensity will change the amount of colour reflected(?)
|
||||||
|
// // from the environment map–can be greater than 1 for more intensity
|
||||||
|
|
||||||
|
// material = new THREE.MeshStandardMaterial({
|
||||||
|
// depthWrite: false
|
||||||
|
// });
|
||||||
|
// material.roughness = 1;
|
||||||
|
// material.metalness = 0.1;
|
||||||
|
// material.envMap = this._world._environment._skybox.getRenderTarget();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const localMesh = new THREE.Mesh(geom, material);
|
||||||
|
// localMesh.rotation.x = -90 * Math.PI / 180;
|
||||||
|
|
||||||
|
// localMesh.receiveShadow = true;
|
||||||
|
|
||||||
|
// mesh.add(localMesh);
|
||||||
|
// mesh.renderOrder = 0.1;
|
||||||
|
|
||||||
|
// mesh.position.x = this._center[0];
|
||||||
|
// mesh.position.z = this._center[1];
|
||||||
|
|
||||||
|
// // const box = new BoxHelper(localMesh);
|
||||||
|
// // mesh.add(box);
|
||||||
|
// //
|
||||||
|
// // mesh.add(this._createDebugMesh());
|
||||||
|
|
||||||
|
// return mesh;
|
||||||
|
// }
|
||||||
|
// _abortRequest() {
|
||||||
|
// if (!this._image) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// this._image.src = '';
|
||||||
|
// }
|
||||||
|
|
||||||
|
// destroy() {
|
||||||
|
// // Cancel any pending requests
|
||||||
|
// this._abortRequest();
|
||||||
|
|
||||||
|
// // Clear image reference
|
||||||
|
// this._image = null;
|
||||||
|
|
||||||
|
// super.destroy();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
|
@ -0,0 +1,22 @@
|
||||||
|
import LRUCache from '../../util/lru-cache';
|
||||||
|
export default class TileCache {
|
||||||
|
constructor(limit = 50) {
|
||||||
|
this._cache = new LRUCache(limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTile(z, x, y) {
|
||||||
|
const key = this._generateKey(z, x, y);
|
||||||
|
return this._cache.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTile(tile, z, x, y) {
|
||||||
|
const key = this._generateKey(z, x, y);
|
||||||
|
this._cache.set(key, tile);
|
||||||
|
}
|
||||||
|
_generateKey(z, x, y) {
|
||||||
|
return [ z, x, y ].join('_');
|
||||||
|
}
|
||||||
|
destory() {
|
||||||
|
this._cache.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
// const r2d = 180 / Math.PI;
|
||||||
|
// const tileURLRegex = /\{([zxy])\}/g;
|
||||||
|
// export class Tile {
|
||||||
|
// constructor(layer, z, x, y) {
|
||||||
|
// this.layer = layer;
|
||||||
|
// this._tile = [ z, x, y ];
|
||||||
|
|
||||||
|
// }
|
||||||
|
// _createMesh() {}
|
||||||
|
// _createDebugMesh() {}
|
||||||
|
|
||||||
|
// _getTileURL(urlParams) {
|
||||||
|
// if (!urlParams.s) {
|
||||||
|
// // Default to a random choice of a, b or c
|
||||||
|
// urlParams.s = String.fromCharCode(97 + Math.floor(Math.random() * 3));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// tileURLRegex.lastIndex = 0;
|
||||||
|
// return this._path.replace(tileURLRegex, function(value, key) {
|
||||||
|
// // Replace with paramter, otherwise keep existing value
|
||||||
|
// return urlParams[key];
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// _tileBoundsFromWGS84(boundsWGS84) {
|
||||||
|
// const sw = this._layer._world.latLonToPoint(LatLon(boundsWGS84[1], boundsWGS84[0]));
|
||||||
|
// const ne = this._layer._world.latLonToPoint(LatLon(boundsWGS84[3], boundsWGS84[2]));
|
||||||
|
|
||||||
|
// return [sw.x, sw.y, ne.x, ne.y];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Get tile bounds in WGS84 coordinates
|
||||||
|
// _tileBoundsWGS84(tile) {
|
||||||
|
// const e = this._tile2lon(tile[0] + 1, tile[2]);
|
||||||
|
// const w = this._tile2lon(tile[0], tile[2]);
|
||||||
|
// const s = this._tile2lat(tile[1] + 1, tile[2]);
|
||||||
|
// const n = this._tile2lat(tile[1], tile[2]);
|
||||||
|
// return [ w, s, e, n ];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// _tile2lon(x, z) {
|
||||||
|
// return x / Math.pow(2, z) * 360 - 180;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// _tile2lat(y, z) {
|
||||||
|
// const n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
|
||||||
|
// return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// _boundsToCenter(bounds) {
|
||||||
|
// const x = bounds[0] + (bounds[2] - bounds[0]) / 2;
|
||||||
|
// const y = bounds[1] + (bounds[3] - bounds[1]) / 2;
|
||||||
|
|
||||||
|
// return [ x, y ];
|
||||||
|
// }
|
||||||
|
// destory() {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -128,6 +128,9 @@ export default class GaodeMap extends Base {
|
||||||
scene.setZoom = zoom => {
|
scene.setZoom = zoom => {
|
||||||
return map.setZoom(zoom);
|
return map.setZoom(zoom);
|
||||||
};
|
};
|
||||||
|
scene.getBounds = () => {
|
||||||
|
return map.getBounds();
|
||||||
|
};
|
||||||
scene.setZoomAndCenter = (zoom, center) => {
|
scene.setZoomAndCenter = (zoom, center) => {
|
||||||
const lnglat = new AMap.LngLat(center[0], center[1]);
|
const lnglat = new AMap.LngLat(center[0], center[1]);
|
||||||
return map.setZoomAndCenter(zoom, lnglat);
|
return map.setZoomAndCenter(zoom, lnglat);
|
||||||
|
@ -138,6 +141,9 @@ export default class GaodeMap extends Base {
|
||||||
scene.setRotation = rotation => {
|
scene.setRotation = rotation => {
|
||||||
return map.setRotation(rotation);
|
return map.setRotation(rotation);
|
||||||
};
|
};
|
||||||
|
scene.setStatus = status => {
|
||||||
|
return map.setStatus(status);
|
||||||
|
};
|
||||||
scene.zoomIn = () => {
|
scene.zoomIn = () => {
|
||||||
return map.zoomIn();
|
return map.zoomIn();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import * as turfMeta from '@turf/meta';
|
import * as turfMeta from '@turf/meta';
|
||||||
import { default as cleanCoords } from '@turf/clean-coords';
|
|
||||||
import { getCoords } from '@turf/invariant';
|
import { getCoords } from '@turf/invariant';
|
||||||
|
|
||||||
export default function geoJSON(data) {
|
export default function geoJSON(data) {
|
||||||
const resultData = [];
|
const resultData = [];
|
||||||
turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个
|
turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个
|
||||||
const coord = getCoords(cleanCoords(currentFeature));
|
const coord = getCoords(currentFeature);
|
||||||
const dataItem = {
|
const dataItem = {
|
||||||
...currentFeature.properties,
|
...currentFeature.properties,
|
||||||
coordinates: coord,
|
coordinates: coord,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Supercluster from 'supercluster';
|
import Supercluster from 'supercluster';
|
||||||
export function cluster(data, option) {
|
export function cluster(data, option) {
|
||||||
const { radius = 40, maxZoom = 16, minZoom = 0, field, zoom = 2 } = option;
|
const { radius = 80, maxZoom = 18, minZoom = 0, field, zoom = 2 } = option;
|
||||||
if (data.pointIndex) {
|
if (data.pointIndex) {
|
||||||
const clusterPoint = data.pointIndex.getClusters(data.extent, zoom);
|
const clusterPoint = data.pointIndex.getClusters(data.extent, zoom);
|
||||||
data.dataArray = formatData(clusterPoint);
|
data.dataArray = formatData(clusterPoint);
|
||||||
|
@ -38,10 +38,9 @@ export function cluster(data, option) {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
data.dataArray = resultData;
|
data.dataArray = resultData;
|
||||||
data.pointIndex = pointIndex;
|
return { data, pointIndex };
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
function formatData(clusterPoint) {
|
export function formatData(clusterPoint) {
|
||||||
return clusterPoint.map((point, index) => {
|
return clusterPoint.map((point, index) => {
|
||||||
return {
|
return {
|
||||||
coordinates: point.geometry.coordinates,
|
coordinates: point.geometry.coordinates,
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import * as _ from '@antv/util';
|
||||||
|
export default function diff(a, b) {
|
||||||
|
// Throw is a or b are not objects.
|
||||||
|
if (!_.isPlainObject(a)) {
|
||||||
|
throw new Error('First parameter to diff() is not an object');
|
||||||
|
}
|
||||||
|
if (!_.isPlainObject(b)) {
|
||||||
|
throw new Error('Second parameter to diff() is not an object');
|
||||||
|
}
|
||||||
|
|
||||||
|
const changes = [];
|
||||||
|
const keysA = _.keys(a);
|
||||||
|
const keysB = _.keys(b);
|
||||||
|
|
||||||
|
// Find the items in A that are not in B.
|
||||||
|
_.each(_.difference(keysA, keysB), key => {
|
||||||
|
changes.push({ type: 'remove', key, value: a[key] });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Find the items in B that are not in A.
|
||||||
|
_.each(_.difference(keysB, keysA), key => {
|
||||||
|
changes.push({ type: 'add', key, value: b[key] });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Find the items that are in both, but have changed.
|
||||||
|
_.each(intersection(keysA, keysB), key => {
|
||||||
|
if (!_.isEqual(a[key], b[key])) {
|
||||||
|
changes.push({ type: 'update', key, value: b[key] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
function intersection(keysA, keysB) {
|
||||||
|
return keysA.filter(key => {
|
||||||
|
return keysB.indexOf(key) > -1;
|
||||||
|
});
|
||||||
|
}
|
|
@ -41,3 +41,73 @@ export function buildMapping({
|
||||||
canvasHeight: nextPowOfTwo(yOffset + (row + 1) * rowHeight)
|
canvasHeight: nextPowOfTwo(yOffset + (row + 1) * rowHeight)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildRowMapping(mapping, columns, yOffset) {
|
||||||
|
for (let i = 0; i < columns.length; i++) {
|
||||||
|
const { icon, xOffset } = columns[i];
|
||||||
|
mapping[icon.id] = Object.assign({}, icon, {
|
||||||
|
x: xOffset,
|
||||||
|
y: yOffset,
|
||||||
|
image: icon.image
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function resizeImage(ctx, imageData, width, height) {
|
||||||
|
const { naturalWidth, naturalHeight } = imageData;
|
||||||
|
if (width === naturalWidth && height === naturalHeight) {
|
||||||
|
return imageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.canvas.height = height;
|
||||||
|
ctx.canvas.width = width;
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||||
|
|
||||||
|
// image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight
|
||||||
|
ctx.drawImage(imageData, 0, 0, naturalWidth, naturalHeight, 0, 0, width, height);
|
||||||
|
|
||||||
|
return ctx.canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildIconMaping({ icons, buffer, maxCanvasWidth }) {
|
||||||
|
let xOffset = 0;
|
||||||
|
let yOffset = 0;
|
||||||
|
let rowHeight = 0;
|
||||||
|
let columns = [];
|
||||||
|
const mapping = {};
|
||||||
|
for (let i = 0; i < icons.length; i++) {
|
||||||
|
const icon = icons[i];
|
||||||
|
if (!mapping[icon.id]) {
|
||||||
|
const { height, width } = icon;
|
||||||
|
|
||||||
|
// fill one row
|
||||||
|
if (xOffset + width + buffer > maxCanvasWidth) {
|
||||||
|
buildRowMapping(mapping, columns, yOffset);
|
||||||
|
|
||||||
|
xOffset = 0;
|
||||||
|
yOffset = rowHeight + yOffset + buffer;
|
||||||
|
rowHeight = 0;
|
||||||
|
columns = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
columns.push({
|
||||||
|
icon,
|
||||||
|
xOffset
|
||||||
|
});
|
||||||
|
|
||||||
|
xOffset = xOffset + width + buffer;
|
||||||
|
rowHeight = Math.max(rowHeight, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (columns.length > 0) {
|
||||||
|
buildRowMapping(mapping, columns, yOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
const canvasHeight = nextPowOfTwo(rowHeight + yOffset + buffer);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mapping,
|
||||||
|
canvasHeight
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
import CommonUtil from './common';
|
|
||||||
import DomUtil from './dom';
|
|
||||||
|
|
||||||
const Util = {};
|
|
||||||
|
|
||||||
CommonUtil.merge(Util, CommonUtil, DomUtil, {
|
|
||||||
mixin(c, mixins) {
|
|
||||||
const Param = c.CFG ? 'CFG' : 'ATTRS';
|
|
||||||
if (c && mixins) {
|
|
||||||
c._mixins = mixins;
|
|
||||||
c[Param] = c[Param] || {};
|
|
||||||
const temp = {};
|
|
||||||
Util.each(mixins, function(mixin) {
|
|
||||||
Util.augment(c, mixin);
|
|
||||||
const attrs = mixin[Param];
|
|
||||||
if (attrs) {
|
|
||||||
Util.merge(temp, attrs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
c[Param] = Util.merge(temp, c[Param]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Util;
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* LRU Cache class with limit
|
||||||
|
*
|
||||||
|
* Update order for each get/set operation
|
||||||
|
* Delete oldest when reach given limit
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class LRUCache {
|
||||||
|
constructor(limit = 5) {
|
||||||
|
this.limit = limit;
|
||||||
|
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this._cache = {};
|
||||||
|
// access/update order, first item is oldest, last item is newest
|
||||||
|
this._order = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key) {
|
||||||
|
const value = this._cache[key];
|
||||||
|
if (value) {
|
||||||
|
// update order
|
||||||
|
this._deleteOrder(key);
|
||||||
|
this._appendOrder(key);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key, value) {
|
||||||
|
if (!this._cache[key]) {
|
||||||
|
// if reach limit, delete the oldest
|
||||||
|
if (Object.keys(this._cache).length === this.limit) {
|
||||||
|
this.delete(this._order[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._cache[key] = value;
|
||||||
|
this._appendOrder(key);
|
||||||
|
} else {
|
||||||
|
// if found in cache, delete the old one, insert new one to the first of list
|
||||||
|
this.delete(key);
|
||||||
|
|
||||||
|
this._cache[key] = value;
|
||||||
|
this._appendOrder(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(key) {
|
||||||
|
const value = this._cache[key];
|
||||||
|
if (value) {
|
||||||
|
this._deleteCache(key);
|
||||||
|
this._deleteOrder(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_deleteCache(key) {
|
||||||
|
delete this._cache[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
_deleteOrder(key) {
|
||||||
|
const index = this._order.findIndex(o => o === key);
|
||||||
|
if (index >= 0) {
|
||||||
|
this._order.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_appendOrder(key) {
|
||||||
|
this._order.push(key);
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,8 +22,8 @@ describe('test shader module', function() {
|
||||||
registerModule('common', commonModule);
|
registerModule('common', commonModule);
|
||||||
registerModule('module1', module1);
|
registerModule('module1', module1);
|
||||||
it('should import a module correctly.', function() {
|
it('should import a module correctly.', function() {
|
||||||
// expect(vs).eq('#define PI 3.14');
|
// expect(vs).eq('#define PI 3.14');
|
||||||
// expect(fs.replace(/(\s+)|(\n)+|(\r\n)+/g, '')).eqls('#ifdefGL_FRAGMENT_PRECISION_HIGHprecisionhighpfloat;#elseprecisionmediumpfloat;#endif');
|
// expect(fs.replace(/(\s+)|(\n)+|(\r\n)+/g, '')).eqls('#ifdefGL_FRAGMENT_PRECISION_HIGHprecisionhighpfloat;#elseprecisionmediumpfloat;#endif');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { pointData } from '../../../asset/data/point';
|
import { pointData } from '../../../asset/data/point';
|
||||||
import { cluster } from '../../../../src/source/transform/cluster';
|
import { cluster } from '../../../../src/source/transform/cluster';
|
||||||
describe('hexagon Test', function() {
|
describe('cluster Test', function() {
|
||||||
|
|
||||||
it('pointToCuster', function() {
|
it('pointToCuster', function() {
|
||||||
const dataArray = pointData.map(item => {
|
const dataArray = pointData.map(item => {
|
||||||
|
@ -17,7 +17,7 @@ describe('hexagon Test', function() {
|
||||||
dataArray,
|
dataArray,
|
||||||
extent: [ -180, -85, 180, 85 ]
|
extent: [ -180, -85, 180, 85 ]
|
||||||
};
|
};
|
||||||
const grid = cluster(data, { radius: 40, field: 'v', zoom: 13 });
|
const grid = cluster(data, { radius: 40, field: 'v', zoom: 13, bbox: [ -180, -85, 180, 85 ] });
|
||||||
expect(grid.dataArray.length).eql(26);
|
expect(grid.data.dataArray.length).eql(26);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|