refactor(src) file name
|
@ -8,9 +8,7 @@ node_modules/
|
||||||
demos/assets/
|
demos/assets/
|
||||||
demos/index.html
|
demos/index.html
|
||||||
demos/*
|
demos/*
|
||||||
<<<<<<< HEAD
|
|
||||||
rollup/*
|
rollup/*
|
||||||
webpack/*
|
webpack/*
|
||||||
=======
|
|
||||||
src/core/three.js
|
src/core/three.js
|
||||||
>>>>>>> master
|
testdemo/*
|
|
@ -75,3 +75,4 @@ demos/image
|
||||||
.vscode
|
.vscode
|
||||||
demos/hexagon.html
|
demos/hexagon.html
|
||||||
demos/model
|
demos/model
|
||||||
|
testdemo
|
|
@ -16,6 +16,6 @@ $ npm run dev
|
||||||
$ npm run demos
|
$ npm run demos
|
||||||
```
|
```
|
||||||
visit online demo
|
visit online demo
|
||||||
http://site.alipay.net/datavis/L7/demos/index.html
|
https://antv.alipay.com/zh-cn/l7/1.x/demo/index.html
|
||||||
|
|
||||||
## How to Contribute
|
## How to Contribute
|
||||||
|
|
|
@ -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,55 +24,79 @@
|
||||||
<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(),
|
||||||
yellow:["#FFFFE8", "#FFFECC", "#FAF896", "#F7E463", "#F0CE3A", "#DBB125", "#C29117", "#AD7410", "#87500C", "#613000"].reverse(),
|
yellow:["#FFFFE8", "#FFFECC", "#FAF896", "#F7E463", "#F0CE3A", "#DBB125", "#C29117", "#AD7410", "#87500C", "#613000"].reverse(),
|
||||||
purple:["#FCF2FF", "#F5DEFF", "#DDB3F2", "#BE7BE3", "#9B4ECF", "#7737B3", "#5B2899", "#411C85", "#270F5E", "#100338"].reverse()
|
purple:["#FCF2FF", "#F5DEFF", "#DDB3F2", "#BE7BE3", "#9B4ECF", "#7737B3", "#5B2899", "#411C85", "#270F5E", "#100338"].reverse()
|
||||||
}
|
}
|
||||||
|
var mapinstance = new AMap.Map('map',{
|
||||||
|
center: [ 120.19382669582967, 30.258134 ],
|
||||||
|
viewMode: '3D',
|
||||||
|
pitch: 0,
|
||||||
|
zoom: 12,
|
||||||
|
maxZoom:20,
|
||||||
|
minZoom:0,
|
||||||
|
});
|
||||||
|
|
||||||
const scene = new L7.Scene({
|
const scene = new L7.Scene({
|
||||||
id: 'map',
|
id: 'map',
|
||||||
mapStyle: 'light', // 样式URL
|
mapStyle: 'dark', // 样式URL
|
||||||
|
map:mapinstance,
|
||||||
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,{
|
||||||
scale:{
|
isCluster:true
|
||||||
min:0,
|
|
||||||
max:1000,
|
|
||||||
type:'linear'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.shape('2d:circle')
|
// .shape('circle')
|
||||||
.size('value', [ 2, 80]) // default 1
|
.shape('point_count', [ 'circle', 'triangle', 'hexagon' ])
|
||||||
|
// .shape('triangle')
|
||||||
|
// .shape('square')
|
||||||
|
// .shape('hexagon')
|
||||||
|
// .shape('octogon')
|
||||||
|
// .shape('hexagram')
|
||||||
|
// .shape('pentagon')
|
||||||
|
.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',["#002466","#105CB3","#2894E0","#CFF6FF","#FFF5B8","#FFAB5C","#F27049","#730D1C"])
|
||||||
return field_8 * 1 > 500;
|
|
||||||
})
|
|
||||||
.color('type', colorObj.blue)
|
|
||||||
.style({
|
.style({
|
||||||
stroke: 'rgb(255,255,255)',
|
stroke: 'rgb(255,255,255)',
|
||||||
strokeWidth: 1,
|
strokeWidth: 2,
|
||||||
opacity: 1.
|
opacity: 1
|
||||||
})
|
})
|
||||||
.render();
|
.render();
|
||||||
|
window.circleLayer = circleLayer;
|
||||||
circleLayer.on('click',(e)=>{
|
const layerText = scene.PointLayer({
|
||||||
console.log(e);
|
zIndex: 3
|
||||||
})
|
})
|
||||||
|
.source(circleLayer.layerSource)
|
||||||
|
.shape('point_count', 'text')
|
||||||
|
.active(false)
|
||||||
|
.filter('point_count',(p)=>{
|
||||||
|
return p > 50
|
||||||
|
})
|
||||||
|
.size('point_count', [ 5, 20]) // default 1
|
||||||
|
.color('#fff')
|
||||||
|
.style({
|
||||||
|
stroke: '#999',
|
||||||
|
strokeWidth: 1,
|
||||||
|
opacity: 1.0
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
console.log(layerText);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,7 +30,7 @@ const scene = new L7.Scene({
|
||||||
});
|
});
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
$.get('https://gw.alipayobjects.com/os/rmsportal/oVTMqfzuuRFKiDwhPSFL.json', data => {
|
$.get('https://gw.alipayobjects.com/os/rmsportal/oVTMqfzuuRFKiDwhPSFL.json', data => {
|
||||||
scene.PointLayer({
|
window.layer = scene.PointLayer({
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
})
|
})
|
||||||
.source(data.list, {
|
.source(data.list, {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -30,8 +30,7 @@ const scene = new L7.Scene({
|
||||||
zoom: 14.82,
|
zoom: 14.82,
|
||||||
});
|
});
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
$.get('./data/contour.geojson', data => {
|
$.get('https://gw.alipayobjects.com/os/rmsportal/ZVfOvhVCzwBkISNsuKCc.json', data => {
|
||||||
// data.features = data.features.slice(0,1);
|
|
||||||
scene.LineLayer({
|
scene.LineLayer({
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
})
|
})
|
||||||
|
|
|
@ -59,6 +59,7 @@ $.getJSON('https://gw.alipayobjects.com/os/rmsportal/kwUdcXnxQtexeGRvTGtA.json',
|
||||||
})
|
})
|
||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
$.getJSON('https://gw.alipayobjects.com/os/rmsportal/dzpMOiLYBKxpdmsgBLoE.json', contourData => {
|
$.getJSON('https://gw.alipayobjects.com/os/rmsportal/dzpMOiLYBKxpdmsgBLoE.json', contourData => {
|
||||||
const landlayer = scene.LineLayer(
|
const landlayer = scene.LineLayer(
|
||||||
{zIndex:2}
|
{zIndex:2}
|
||||||
|
@ -72,6 +73,7 @@ $.getJSON('https://gw.alipayobjects.com/os/rmsportal/dzpMOiLYBKxpdmsgBLoE.json',
|
||||||
})
|
})
|
||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
$.getJSON('https://gw.alipayobjects.com/os/rmsportal/opYqFyDGyGUAUXkLUhBV.json', city => {
|
$.getJSON('https://gw.alipayobjects.com/os/rmsportal/opYqFyDGyGUAUXkLUhBV.json', city => {
|
||||||
var makerLayer = scene.PointLayer({
|
var makerLayer = scene.PointLayer({
|
||||||
zIndex: 4
|
zIndex: 4
|
||||||
|
@ -81,7 +83,6 @@ $.getJSON('https://gw.alipayobjects.com/os/rmsportal/opYqFyDGyGUAUXkLUhBV.json',
|
||||||
.shape('image:local')
|
.shape('image:local')
|
||||||
.color('#0D408C')
|
.color('#0D408C')
|
||||||
.render();
|
.render();
|
||||||
|
|
||||||
var makerText = scene.PointLayer({
|
var makerText = scene.PointLayer({
|
||||||
zIndex: 8,
|
zIndex: 8,
|
||||||
minZoom:5,
|
minZoom:5,
|
||||||
|
@ -96,6 +97,7 @@ $.getJSON('https://gw.alipayobjects.com/os/rmsportal/opYqFyDGyGUAUXkLUhBV.json',
|
||||||
strokeWidth: 4,
|
strokeWidth: 4,
|
||||||
})
|
})
|
||||||
.render();
|
.render();
|
||||||
|
return
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -94,9 +94,9 @@ scene.on('loaded', () => {
|
||||||
.style({
|
.style({
|
||||||
opacity: 1.0
|
opacity: 1.0
|
||||||
})
|
})
|
||||||
.render();
|
//.render();
|
||||||
|
|
||||||
|
|
||||||
|
console.log(citylayer);
|
||||||
citylayer.on('click',(e)=>{
|
citylayer.on('click',(e)=>{
|
||||||
$("#info").css({'left': e.pixel.x,'top':e.pixel.y, display:'block'});
|
$("#info").css({'left': e.pixel.x,'top':e.pixel.y, display:'block'});
|
||||||
$("#info").html(`<p>${e.feature.properties.area || e.feature.properties.name }<span">${e.feature.properties.pm2_5_24h || 0}</span></p>`);
|
$("#info").html(`<p>${e.feature.properties.area || e.feature.properties.name }<span">${e.feature.properties.pm2_5_24h || 0}</span></p>`);
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
<!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>hexagon demo</title>
|
||||||
|
<style>
|
||||||
|
body {margin: 0;}
|
||||||
|
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="map"></div>
|
||||||
|
<div id ="info" class ="tooltip" style="display:none"></div>
|
||||||
|
<div class='info-panel top-right'>
|
||||||
|
<p>
|
||||||
|
<label>min</label><input name="minaqi" type="range" step="1" min="0" max="200" value=0> <label>0</label>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label>max</label><input name="maxaqi" type="range" step="1" min="0" max="300" value=300><label>300</label>
|
||||||
|
</p>
|
||||||
|
<p><label>color</label><select>
|
||||||
|
<option value ="default">default</option>
|
||||||
|
<option value ="blue">blue</option>
|
||||||
|
<option value ="red">red</option>
|
||||||
|
<option value="orange">orange</option>
|
||||||
|
<option value="green">green</option>
|
||||||
|
<option value="yellow">yellow</option>
|
||||||
|
<option value="purple">purple</option>
|
||||||
|
</select> </p>
|
||||||
|
<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>
|
||||||
|
const colorObj ={
|
||||||
|
blue: ["#E8FCFF", "#CFF6FF", "#98E3FA", "#65CEF7", "#3CB4F0", "#2894E0", "#1A76C7", "#105CB3", "#0D408C", "#002466"],
|
||||||
|
red: ["#FFF4F2", "#FFDFDB", "#FAADAA", "#F77472", "#F04850", "#D63147", "#BD223E", "#A81642", "#820C37", "#5C0023"],
|
||||||
|
orange:["#FFF7EB", "#FFECD4", "#FAD09D", "#F7B16A", "#F08D41", "#DB6C2C", "#C2491D", "#AD2B11", "#871D0C", "#610800"],
|
||||||
|
green:["#FAFFF0", "#EBF7D2", "#C8E695", "#A5D660", "#7DC238", "#59A616", "#3F8C0B", "#237804", "#125200", "#082B00"],
|
||||||
|
yellow:["#FFFFE8", "#FFFECC", "#FAF896", "#F7E463", "#F0CE3A", "#DBB125", "#C29117", "#AD7410", "#87500C", "#613000"],
|
||||||
|
purple:["#FCF2FF", "#F5DEFF", "#DDB3F2", "#BE7BE3", "#9B4ECF", "#7737B3", "#5B2899", "#411C85", "#270F5E", "#100338"],
|
||||||
|
}
|
||||||
|
|
||||||
|
const scene = new L7.Scene({
|
||||||
|
id: 'map',
|
||||||
|
mapStyle: 'dark', // 样式URL
|
||||||
|
center: [104.838088,34.075889 ],
|
||||||
|
pitch: 0,
|
||||||
|
zoom: 4.5,
|
||||||
|
|
||||||
|
});
|
||||||
|
window.scene = scene;
|
||||||
|
scene.on('loaded', () => {
|
||||||
|
var colors = ["#FFF5B8","#FFDC7D","#FFAB5C","#F27049","#D42F31","#730D1C"];
|
||||||
|
$.getJSON('https://gw.alipayobjects.com/os/basement_prod/77497aa8-8dd0-4a0c-bf3b-3bb55c5d453c.json', city => {
|
||||||
|
|
||||||
|
const citylayer = scene.PolygonLayer()
|
||||||
|
.source(city)
|
||||||
|
.color('#F27049')
|
||||||
|
.shape('fill')
|
||||||
|
.active(true)
|
||||||
|
.style({
|
||||||
|
opacity: 0.8
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
|
||||||
|
const citylayer2 = scene.PolygonLayer()
|
||||||
|
.source(city)
|
||||||
|
.shape('line')
|
||||||
|
.color('#fff')
|
||||||
|
.style({
|
||||||
|
opacity: 1.0
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
|
||||||
|
console.log(citylayer);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -26,9 +26,9 @@ const scene = new L7.Scene({
|
||||||
id: 'map',
|
id: 'map',
|
||||||
viewMode: '3D',
|
viewMode: '3D',
|
||||||
mapStyle: 'amap://styles/ba3e9759545cd618392ef073c0dfda8c?isPublic=true', // 样式URL
|
mapStyle: 'amap://styles/ba3e9759545cd618392ef073c0dfda8c?isPublic=true', // 样式URL
|
||||||
center: [ 110.770672, 34.159869 ],
|
center: [ 110.770672, 44.159869 ],
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
zoom: 4
|
zoom: 3
|
||||||
});
|
});
|
||||||
|
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
|
@ -42,10 +42,9 @@ scene.on('loaded', () => {
|
||||||
const blob = this.response;
|
const blob = this.response;
|
||||||
const tiff = GeoTIFF.parse(blob);
|
const tiff = GeoTIFF.parse(blob);
|
||||||
const image = tiff.getImage();
|
const image = tiff.getImage();
|
||||||
const values = image.readRasters()[0];
|
const values = image.readRasters()[0].values();
|
||||||
const m = image.getHeight();
|
const m = image.getHeight();
|
||||||
const n = image.getWidth();
|
const n = image.getWidth();
|
||||||
|
|
||||||
const layer = scene.RasterLayer({ zIndex: 2 }).
|
const layer = scene.RasterLayer({ zIndex: 2 }).
|
||||||
source(values, {
|
source(values, {
|
||||||
parser: {
|
parser: {
|
||||||
|
@ -64,11 +63,7 @@ scene.on('loaded', () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.render();
|
.render();
|
||||||
setTimeout(()=>{
|
console.log(layer);
|
||||||
layer.style({
|
|
||||||
rampColors: 'viridis',
|
|
||||||
}).render();
|
|
||||||
},3000)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,22 +25,23 @@ const scene = new L7.Scene({
|
||||||
mapStyle: 'dark', // 样式URL
|
mapStyle: 'dark', // 样式URL
|
||||||
center: [ 120.19382669582967, 30.258134 ],
|
center: [ 120.19382669582967, 30.258134 ],
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
zoom: 3
|
zoom: 1
|
||||||
});
|
});
|
||||||
window.scene = scene;
|
window.scene = scene;
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
$.get('./data/provincePoint.geojson', data => {
|
$.get('./data/provincePoint.json', data => {
|
||||||
scene.PointLayer({
|
scene.PointLayer({
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
})
|
})
|
||||||
.source(data)
|
.source(data)
|
||||||
.shape('name', 'text')
|
.shape('name', 'text')
|
||||||
|
.active(true)
|
||||||
.size(12) // default 1
|
.size(12) // default 1
|
||||||
.color('#fff')
|
.color('name')
|
||||||
.style({
|
.style({
|
||||||
stroke: '#999',
|
stroke: '#999',
|
||||||
strokeWidth: 2,
|
strokeWidth: 0,
|
||||||
opacity: 0.85
|
opacity: 1.0
|
||||||
})
|
})
|
||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,35 +32,35 @@ const scene = new L7.Scene({
|
||||||
});
|
});
|
||||||
window.scene = scene;
|
window.scene = scene;
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
$.get('https://gw.alipayobjects.com/os/rmsportal/XHMbjQwrSrajvLLvMPbK.json', data => {
|
// $.get('https://gw.alipayobjects.com/os/rmsportal/XHMbjQwrSrajvLLvMPbK.json', data => {
|
||||||
scene.PolygonLayer({
|
// scene.PolygonLayer({
|
||||||
zIndex: 0
|
// zIndex: 0
|
||||||
})
|
// })
|
||||||
.source(data)
|
// .source(data)
|
||||||
.shape('fill')
|
// .shape('fill')
|
||||||
.active({fill:'blue'})
|
// .active({fill:'blue'})
|
||||||
.color('rgb(79,174,234)')
|
// .color('rgb(79,174,234)')
|
||||||
.render();
|
// .render();
|
||||||
});
|
// });
|
||||||
$.get('https://gw.alipayobjects.com/os/rmsportal/VifgwJEyBIXnDrjCwWdK.json', data => {
|
// $.get('https://gw.alipayobjects.com/os/rmsportal/VifgwJEyBIXnDrjCwWdK.json', data => {
|
||||||
scene.PolygonLayer({
|
// scene.PolygonLayer({
|
||||||
zIndex: 0
|
// zIndex: 0
|
||||||
})
|
// })
|
||||||
.source(data)
|
// .source(data)
|
||||||
.shape('fill')
|
// .shape('fill')
|
||||||
.color('rgb(156,194,116)')
|
// .color('rgb(156,194,116)')
|
||||||
.render();
|
// .render();
|
||||||
});
|
// });
|
||||||
$.get('https://gw.alipayobjects.com/os/rmsportal/ZseLNWMOPGrgqQYfvtli.json', data => {
|
// $.get('https://gw.alipayobjects.com/os/rmsportal/ZseLNWMOPGrgqQYfvtli.json', data => {
|
||||||
scene.LineLayer({
|
// scene.LineLayer({
|
||||||
zIndex: 2
|
// zIndex: 2
|
||||||
})
|
// })
|
||||||
.source(data)
|
// .source(data)
|
||||||
.shape('line')
|
// .shape('line')
|
||||||
.size([3,0])
|
// .size([3,0])
|
||||||
.color('rgb(79,174,234)')
|
// .color('rgb(79,174,234)')
|
||||||
.render();
|
// .render();
|
||||||
});
|
// });
|
||||||
|
|
||||||
$.get('https://gw.alipayobjects.com/os/rmsportal/ggFwDClGjjvpSMBIrcEx.json', data => {
|
$.get('https://gw.alipayobjects.com/os/rmsportal/ggFwDClGjjvpSMBIrcEx.json', data => {
|
||||||
citylayer = scene.PolygonLayer({
|
citylayer = scene.PolygonLayer({
|
||||||
|
@ -69,6 +69,24 @@ scene.on('loaded', () => {
|
||||||
.source(data)
|
.source(data)
|
||||||
.shape('extrude')
|
.shape('extrude')
|
||||||
.active({fill:'red'})
|
.active({fill:'red'})
|
||||||
|
.style({
|
||||||
|
lights: [
|
||||||
|
{
|
||||||
|
type: 'directional',
|
||||||
|
direction: [ 1, 10.5, 12 ],
|
||||||
|
ambient: [ 0.2, 0.2, 0.2 ],
|
||||||
|
diffuse: 'red',
|
||||||
|
specular: [ 0.1, 0.1, 0.1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'directional',
|
||||||
|
direction: [ 1, -10.5, 12 ],
|
||||||
|
ambient: [ 0.2, 0.2, 0.2 ],
|
||||||
|
diffuse: 'green',
|
||||||
|
specular: [ 0.1, 0.1, 0.1 ]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
.size('floor',[10,2000])
|
.size('floor',[10,2000])
|
||||||
.color('rgba(242,246,250,0.96)')
|
.color('rgba(242,246,250,0.96)')
|
||||||
.render();
|
.render();
|
||||||
|
|
|
@ -41,7 +41,7 @@ scene.on('loaded', () => {
|
||||||
features.push(greatCircle);
|
features.push(greatCircle);
|
||||||
}
|
}
|
||||||
var fc = turf.featureCollection(features);
|
var fc = turf.featureCollection(features);
|
||||||
scene.LineLayer({
|
const layer = scene.LineLayer({
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
})
|
})
|
||||||
.source(fc)
|
.source(fc)
|
||||||
|
@ -51,6 +51,7 @@ scene.on('loaded', () => {
|
||||||
})
|
})
|
||||||
//.animate({enable:true})
|
//.animate({enable:true})
|
||||||
.render();
|
.render();
|
||||||
|
console.log(layer);
|
||||||
/**
|
/**
|
||||||
scene.LineLayer({
|
scene.LineLayer({
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ColorHash = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||||
|
/**
|
||||||
|
* BKDR Hash (modified version)
|
||||||
|
*
|
||||||
|
* @param {String} str string to hash
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
var BKDRHash = function(str) {
|
||||||
|
var seed = 131;
|
||||||
|
var seed2 = 137;
|
||||||
|
var hash = 0;
|
||||||
|
// make hash more sensitive for short string like 'a', 'b', 'c'
|
||||||
|
str += 'x';
|
||||||
|
// Note: Number.MAX_SAFE_INTEGER equals 9007199254740991
|
||||||
|
var MAX_SAFE_INTEGER = parseInt(9007199254740991 / seed2);
|
||||||
|
for(var i = 0; i < str.length; i++) {
|
||||||
|
if(hash > MAX_SAFE_INTEGER) {
|
||||||
|
hash = parseInt(hash / seed2);
|
||||||
|
}
|
||||||
|
hash = hash * seed + str.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = BKDRHash;
|
||||||
|
|
||||||
|
},{}],2:[function(require,module,exports){
|
||||||
|
var BKDRHash = require('./bkdr-hash');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert RGB Array to HEX
|
||||||
|
*
|
||||||
|
* @param {Array} RGBArray - [R, G, B]
|
||||||
|
* @returns {String} 6 digits hex starting with #
|
||||||
|
*/
|
||||||
|
var RGB2HEX = function(RGBArray) {
|
||||||
|
var hex = '#';
|
||||||
|
RGBArray.forEach(function(value) {
|
||||||
|
if (value < 16) {
|
||||||
|
hex += 0;
|
||||||
|
}
|
||||||
|
hex += value.toString(16);
|
||||||
|
});
|
||||||
|
return hex;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert HSL to RGB
|
||||||
|
*
|
||||||
|
* @see {@link http://zh.wikipedia.org/wiki/HSL和HSV色彩空间} for further information.
|
||||||
|
* @param {Number} H Hue ∈ [0, 360)
|
||||||
|
* @param {Number} S Saturation ∈ [0, 1]
|
||||||
|
* @param {Number} L Lightness ∈ [0, 1]
|
||||||
|
* @returns {Array} R, G, B ∈ [0, 255]
|
||||||
|
*/
|
||||||
|
var HSL2RGB = function(H, S, L) {
|
||||||
|
H /= 360;
|
||||||
|
|
||||||
|
var q = L < 0.5 ? L * (1 + S) : L + S - L * S;
|
||||||
|
var p = 2 * L - q;
|
||||||
|
|
||||||
|
return [H + 1/3, H, H - 1/3].map(function(color) {
|
||||||
|
if(color < 0) {
|
||||||
|
color++;
|
||||||
|
}
|
||||||
|
if(color > 1) {
|
||||||
|
color--;
|
||||||
|
}
|
||||||
|
if(color < 1/6) {
|
||||||
|
color = p + (q - p) * 6 * color;
|
||||||
|
} else if(color < 0.5) {
|
||||||
|
color = q;
|
||||||
|
} else if(color < 2/3) {
|
||||||
|
color = p + (q - p) * 6 * (2/3 - color);
|
||||||
|
} else {
|
||||||
|
color = p;
|
||||||
|
}
|
||||||
|
return Math.round(color * 255);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function isArray(o) {
|
||||||
|
return Object.prototype.toString.call(o) === '[object Array]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color Hash Class
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
var ColorHash = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
var LS = [options.lightness, options.saturation].map(function(param) {
|
||||||
|
param = param || [0.35, 0.5, 0.65]; // note that 3 is a prime
|
||||||
|
return isArray(param) ? param.concat() : [param];
|
||||||
|
});
|
||||||
|
|
||||||
|
this.L = LS[0];
|
||||||
|
this.S = LS[1];
|
||||||
|
|
||||||
|
if (typeof options.hue === 'number') {
|
||||||
|
options.hue = {min: options.hue, max: options.hue};
|
||||||
|
}
|
||||||
|
if (typeof options.hue === 'object' && !isArray(options.hue)) {
|
||||||
|
options.hue = [options.hue];
|
||||||
|
}
|
||||||
|
if (typeof options.hue === 'undefined') {
|
||||||
|
options.hue = [];
|
||||||
|
}
|
||||||
|
this.hueRanges = options.hue.map(function (range) {
|
||||||
|
return {
|
||||||
|
min: typeof range.min === 'undefined' ? 0 : range.min,
|
||||||
|
max: typeof range.max === 'undefined' ? 360: range.max
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
this.hash = options.hash || BKDRHash;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hash in [h, s, l].
|
||||||
|
* Note that H ∈ [0, 360); S ∈ [0, 1]; L ∈ [0, 1];
|
||||||
|
*
|
||||||
|
* @param {String} str string to hash
|
||||||
|
* @returns {Array} [h, s, l]
|
||||||
|
*/
|
||||||
|
ColorHash.prototype.hsl = function(str) {
|
||||||
|
var H, S, L;
|
||||||
|
var hash = this.hash(str);
|
||||||
|
|
||||||
|
if (this.hueRanges.length) {
|
||||||
|
var range = this.hueRanges[hash % this.hueRanges.length];
|
||||||
|
var hueResolution = 727; // note that 727 is a prime
|
||||||
|
H = ((hash / this.hueRanges.length) % hueResolution) * (range.max - range.min) / hueResolution + range.min;
|
||||||
|
} else {
|
||||||
|
H = hash % 359; // note that 359 is a prime
|
||||||
|
}
|
||||||
|
hash = parseInt(hash / 360);
|
||||||
|
S = this.S[hash % this.S.length];
|
||||||
|
hash = parseInt(hash / this.S.length);
|
||||||
|
L = this.L[hash % this.L.length];
|
||||||
|
|
||||||
|
return [H, S, L];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hash in [r, g, b].
|
||||||
|
* Note that R, G, B ∈ [0, 255]
|
||||||
|
*
|
||||||
|
* @param {String} str string to hash
|
||||||
|
* @returns {Array} [r, g, b]
|
||||||
|
*/
|
||||||
|
ColorHash.prototype.rgb = function(str) {
|
||||||
|
var hsl = this.hsl(str);
|
||||||
|
return HSL2RGB.apply(this, hsl);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hash in hex
|
||||||
|
*
|
||||||
|
* @param {String} str string to hash
|
||||||
|
* @returns {String} hex with #
|
||||||
|
*/
|
||||||
|
ColorHash.prototype.hex = function(str) {
|
||||||
|
var rgb = this.rgb(str);
|
||||||
|
return RGB2HEX(rgb);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ColorHash;
|
||||||
|
|
||||||
|
},{"./bkdr-hash":1}]},{},[2])(2)
|
||||||
|
});
|
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 |
|
@ -6,7 +6,7 @@
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<meta name="geometry" content="diagram">
|
<meta name="geometry" content="diagram">
|
||||||
<link rel="stylesheet" href="./assets/common.css">
|
<link rel="stylesheet" href="./assets/common.css">
|
||||||
<title>point_circle</title>
|
<title>dashline demo</title>
|
||||||
<style>
|
<style>
|
||||||
#map { position:absolute; top:0; bottom:0; width:100%; }
|
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||||
</style>
|
</style>
|
||||||
|
@ -20,38 +20,36 @@
|
||||||
<script src="../build/L7.js"></script>
|
<script src="../build/L7.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
const color1 = [ 'rgba(37, 140, 249, 0.8)', 'rgba(14, 241, 242, 0.8)', 'rgba(255, 255, 255, 0.8)' ];
|
||||||
const scene = new L7.Scene({
|
const scene = new L7.Scene({
|
||||||
id: 'map',
|
id: 'map',
|
||||||
mapStyle: 'dark', // 样式URL
|
mapStyle: 'dark', // 样式URL
|
||||||
center: [104.838088,34.075889 ],
|
center: [ 102.602992, 23.107329],
|
||||||
pitch: 0,
|
pitch: 15,
|
||||||
zoom: 9,
|
zoom: 14.82,
|
||||||
minZoom: 8,
|
|
||||||
rotation:0
|
|
||||||
});
|
});
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
scene.image.addImage('local', 'https://gw.alipayobjects.com/zos/rmsportal/xZXhTxbglnuTmZEwqQrE.png');
|
$.get('https://gw.alipayobjects.com/os/rmsportal/ZVfOvhVCzwBkISNsuKCc.json', data => {
|
||||||
$.get('https://gw.alipayobjects.com/os/rmsportal/oVTMqfzuuRFKiDwhPSFL.json', data => {
|
scene.LineLayer({
|
||||||
scene.PointLayer({
|
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
})
|
})
|
||||||
.source(data.list, {
|
.source(data)
|
||||||
type: 'array',
|
.size('ELEV',(value)=>{
|
||||||
x: 'j',
|
return [2,(value-1000)*7];
|
||||||
y: 'w',
|
|
||||||
})
|
})
|
||||||
.shape('m','text')
|
.active(true)
|
||||||
.size(20)
|
.shape('line')
|
||||||
.color('#fff')
|
|
||||||
.style({
|
.style({
|
||||||
stroke:'#fff',
|
lineType: 'dash',
|
||||||
strokeWidth:1.0,
|
dashArray: 200,
|
||||||
opacity:1.0,
|
dashOffset: 0.2,
|
||||||
|
dashRatio: 0.5
|
||||||
})
|
})
|
||||||
|
.color('ELEV',["#E8FCFF", "#CFF6FF", "#A1E9ff", "#65CEF7", "#3CB1F0", "#2894E0", "#1772c2", "#105CB3", "#0D408C", "#002466"].reverse())
|
||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -29,7 +29,7 @@ const scene = new L7.Scene({
|
||||||
});
|
});
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
$.get('https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv', data => {
|
$.get('https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv', data => {
|
||||||
var layer = scene.HeatMapLayer({
|
var layer = scene.HeatmapLayer({
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
})
|
})
|
||||||
.source(data, {
|
.source(data, {
|
||||||
|
@ -59,7 +59,8 @@ scene.on('loaded', () => {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.shape('gird')
|
.shape('grid')
|
||||||
|
.active({fill:'red'})
|
||||||
.style({
|
.style({
|
||||||
coverage: 0.8
|
coverage: 0.8
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
<!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">
|
||||||
|
<title>heatmap</title>
|
||||||
|
<style>
|
||||||
|
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="map"></div>
|
||||||
|
<script src="https://webapi.amap.com/maps?v=1.4.8&key=f28fca5384129d180ad82915156a9baf&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>
|
||||||
|
const scene = new L7.Scene({
|
||||||
|
id: 'map',
|
||||||
|
mapStyle: 'amap://styles/c9f1d10cae34f8ab05e425462c5a58d7', // 样式URL
|
||||||
|
center: [ -155, 60 ],
|
||||||
|
pitch: 0,
|
||||||
|
zoom: 4.5
|
||||||
|
});
|
||||||
|
|
||||||
|
window.scene = scene;
|
||||||
|
scene.on('loaded', () => {
|
||||||
|
$.get('https://gw.alipayobjects.com/os/basement_prod/08c6ea00-dc5f-4bb0-b0b5-52bde5edf0a3.json', data => {
|
||||||
|
scene.HeatmapLayer({
|
||||||
|
zIndex: 2
|
||||||
|
})
|
||||||
|
.source(data)
|
||||||
|
.size('mag', [ 0, 1 ]) // weight映射通道
|
||||||
|
.style({
|
||||||
|
intensity: 10,
|
||||||
|
radius: 10,
|
||||||
|
opacity:1,
|
||||||
|
rampColors: {
|
||||||
|
colors: [ '#ffda45ff', '#fde725ff', '#ffc934ff', '#ffb824ff', '#ffb824ff', '#fa8100ff' ],
|
||||||
|
positions: [ 0, 0.2, 0.4, 0.6, 0.9, 1.0 ]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
/*scene.PointLayer({
|
||||||
|
zIndex: 2
|
||||||
|
})
|
||||||
|
.source(data)
|
||||||
|
.shape('2d:circle')
|
||||||
|
.size(2) // weight映射通道
|
||||||
|
.color('red')
|
||||||
|
.render();*/
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -29,7 +29,7 @@ const scene = new L7.Scene({
|
||||||
});
|
});
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
$.get('https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv', data => {
|
$.get('https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv', data => {
|
||||||
var layer = scene.HeatMapLayer({
|
var layer = scene.HeatmapLayer({
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
})
|
})
|
||||||
.source(data, {
|
.source(data, {
|
||||||
|
|
|
@ -39,7 +39,7 @@ scene.on('loaded', () => {
|
||||||
//.color('#F08D41')
|
//.color('#F08D41')
|
||||||
.color('#ff893a')
|
.color('#ff893a')
|
||||||
.animate({enable:true})
|
.animate({enable:true})
|
||||||
.render();
|
//.render();
|
||||||
});
|
});
|
||||||
$.get('https://gw.alipayobjects.com/os/rmsportal/vmvAxgsEwbpoSWbSYvix.json', data => {
|
$.get('https://gw.alipayobjects.com/os/rmsportal/vmvAxgsEwbpoSWbSYvix.json', data => {
|
||||||
buildLayer = scene.PolygonLayer({
|
buildLayer = scene.PolygonLayer({
|
||||||
|
@ -55,7 +55,23 @@ scene.on('loaded', () => {
|
||||||
baseColor:'rgb(16,16,16)',
|
baseColor:'rgb(16,16,16)',
|
||||||
windowColor:'rgb(30,60,89)',
|
windowColor:'rgb(30,60,89)',
|
||||||
//brightColor:'rgb(155,217,255)'
|
//brightColor:'rgb(155,217,255)'
|
||||||
brightColor:'rgb(255,176,38)'
|
brightColor:'rgb(255,176,38)',
|
||||||
|
lights: [
|
||||||
|
{
|
||||||
|
type: 'directional',
|
||||||
|
direction: [ 1, 10.5, 12 ],
|
||||||
|
ambient: [ 0.2, 0.2, 0.2 ],
|
||||||
|
diffuse: 'red',
|
||||||
|
specular: [ 0.1, 0.1, 0.1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'directional',
|
||||||
|
direction: [ 1, -10.5, 12 ],
|
||||||
|
ambient: [ 0.2, 0.2, 0.2 ],
|
||||||
|
diffuse: 'green',
|
||||||
|
specular: [ 0.1, 0.1, 0.1 ]
|
||||||
|
},
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.render();
|
.render();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
<!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>hexagon demo</title>
|
||||||
|
<style>
|
||||||
|
body {margin: 0;}
|
||||||
|
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||||
|
</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>
|
||||||
|
|
||||||
|
const scene = new L7.Scene({
|
||||||
|
id: 'map',
|
||||||
|
mapStyle: 'light', // 样式URL
|
||||||
|
center: [104.838088,34.075889 ],
|
||||||
|
pitch: 0,
|
||||||
|
hash:true,
|
||||||
|
zoom: 3,
|
||||||
|
|
||||||
|
});
|
||||||
|
window.scene = scene;
|
||||||
|
scene.on('loaded', () => {
|
||||||
|
scene.ImageTileLayer({
|
||||||
|
zIndex:4
|
||||||
|
})
|
||||||
|
.source('http://t1.tianditu.com/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk=174705aebfe31b79b3587279e211cb9a')
|
||||||
|
.render();
|
||||||
|
|
||||||
|
$.getJSON('https://gw.alipayobjects.com/os/rmsportal/JToMOWvicvJOISZFCkEI.json', city => {
|
||||||
|
const citylayer = scene.PolygonLayer(
|
||||||
|
{
|
||||||
|
zIndex:0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.source(city)
|
||||||
|
.active(false)
|
||||||
|
.color('pm2_5_24h',["#FFF5B8","#FFDC7D","#FFAB5C","#F27049","#D42F31","#730D1C"])
|
||||||
|
.shape('fill')
|
||||||
|
.style({
|
||||||
|
opacity: 1.0
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
<!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>hexagon demo</title>
|
||||||
|
<style>
|
||||||
|
body {margin: 0;}
|
||||||
|
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||||
|
</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>
|
||||||
|
|
||||||
|
const scene = new L7.Scene({
|
||||||
|
id: 'map',
|
||||||
|
mapStyle: 'dark', // 样式URL
|
||||||
|
center: [116.5909,39.9225 ],
|
||||||
|
pitch: 0,
|
||||||
|
hash:true,
|
||||||
|
zoom: 14,
|
||||||
|
|
||||||
|
});
|
||||||
|
window.scene = scene;
|
||||||
|
scene.on('loaded', () => {
|
||||||
|
|
||||||
|
const layer = scene.VectorTileLayer({
|
||||||
|
zIndex:0,
|
||||||
|
layerType:'point'
|
||||||
|
})
|
||||||
|
//.source('https://pre-lbs-show.taobao.com/gettile?x={x}&y={y}&z={z}&pipeId=pipe_vt_test')
|
||||||
|
|
||||||
|
// http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/point/{z}/{x}/{y}.pbf
|
||||||
|
// https://mvt.amap.com/district/CHN2/8/203/105/4096?key=
|
||||||
|
.source('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/point2/{z}/{x}/{y}.pbf',{
|
||||||
|
parser:{
|
||||||
|
type: 'mvt',
|
||||||
|
sourceLayer:'layer',
|
||||||
|
// idField:'adcode',
|
||||||
|
maxZoom: 14,
|
||||||
|
minZoom: 13,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.scale({
|
||||||
|
total:{
|
||||||
|
min:0,
|
||||||
|
max:100000,
|
||||||
|
type:'log'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.shape('normal')
|
||||||
|
.size(1)
|
||||||
|
.active({fill:'red'})
|
||||||
|
.color('total', ['#d53e4f','#f46d43','#fdae61','#fee08b','#ffffbf','#e6f598','#abdda4','#66c2a5','#3288bd'].reverse())
|
||||||
|
//.color('#0D408C')
|
||||||
|
.style({
|
||||||
|
stroke: 'rgba(255,255,255,0.8)',
|
||||||
|
strokeWidth: 1,
|
||||||
|
strokeOpacity:0.6,
|
||||||
|
opacity: 1
|
||||||
|
})
|
||||||
|
.render(
|
||||||
|
);
|
||||||
|
layer.on('mousemove',(feature)=>{
|
||||||
|
console.log(feature);
|
||||||
|
})
|
||||||
|
console.log(layer);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
<!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>hexagon demo</title>
|
||||||
|
<style>
|
||||||
|
body {margin: 0;}
|
||||||
|
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||||
|
</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/color-hash.js"></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>
|
||||||
|
|
||||||
|
const scene = new L7.Scene({
|
||||||
|
id: 'map',
|
||||||
|
mapStyle: 'dark', // 样式URL
|
||||||
|
center: [116.5909,39.9225 ],
|
||||||
|
pitch: 0,
|
||||||
|
hash:true,
|
||||||
|
zoom: 4,
|
||||||
|
|
||||||
|
});
|
||||||
|
window.scene = scene;
|
||||||
|
var colorHash = new ColorHash();
|
||||||
|
|
||||||
|
|
||||||
|
scene.on('loaded', () => {
|
||||||
|
|
||||||
|
const layer = scene.VectorTileLayer({
|
||||||
|
zIndex:0,
|
||||||
|
layerType:'polygon'
|
||||||
|
})
|
||||||
|
.source('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/china/province/{z}/{x}/{y}.pbf',{
|
||||||
|
parser:{
|
||||||
|
type: 'mvt',
|
||||||
|
sourceLayer:'layer',
|
||||||
|
idField:'code',
|
||||||
|
maxZoom: 5,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.scale({
|
||||||
|
total:{
|
||||||
|
type:'linear',
|
||||||
|
min:0,
|
||||||
|
max:5000000
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.shape('fill')
|
||||||
|
.size(2)
|
||||||
|
.active(false)
|
||||||
|
.color('total', ['#ffffe5','#fff7bc','#fee391','#fec44f','#fe9929','#ec7014','#cc4c02','#993404','#662506'])
|
||||||
|
.style({
|
||||||
|
opacity:1.0
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<!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>hexagon demo</title>
|
||||||
|
<style>
|
||||||
|
body {margin: 0;}
|
||||||
|
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||||
|
</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>
|
||||||
|
|
||||||
|
const scene = new L7.Scene({
|
||||||
|
id: 'map',
|
||||||
|
mapStyle: 'light', // 样式URL
|
||||||
|
center: [116.5909,39.9225 ],
|
||||||
|
pitch: 0,
|
||||||
|
hash:true,
|
||||||
|
zoom: 16,
|
||||||
|
|
||||||
|
});
|
||||||
|
window.scene = scene;
|
||||||
|
scene.on('loaded', () => {
|
||||||
|
const layer = scene.VectorTileLayer({
|
||||||
|
zIndex:0,
|
||||||
|
layerType:'point'
|
||||||
|
})
|
||||||
|
.source('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/china/all_point/{z}/{x}/{y}.pbf',{
|
||||||
|
parser:{
|
||||||
|
type: 'mvt',
|
||||||
|
sourceLayer:'layer',
|
||||||
|
maxZoom:14,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.scale({
|
||||||
|
bc_grade:{
|
||||||
|
type:'cat',
|
||||||
|
values:[1, 2 ,3, 4]
|
||||||
|
},
|
||||||
|
open_mode:{
|
||||||
|
type:'cat',
|
||||||
|
values:['线上','线下','自助']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.active(false)
|
||||||
|
// 'circle', 'triangle', 'square', 'pentagon', 'hexagon', 'octogon', 'hexagram', 'rhombus', 'vesica'
|
||||||
|
.shape('open_mode', ['circle','hexagon','hexagram'])
|
||||||
|
.size('bc_grade', [2,15])
|
||||||
|
.color('bc_grade', ['#ffffcc','#d9f0a3','#addd8e','#78c679','#31a354','#006837'])
|
||||||
|
.style({
|
||||||
|
stroke: '#fff',
|
||||||
|
strokeWidth: 1.0,
|
||||||
|
strokeOpacity:1.,
|
||||||
|
})
|
||||||
|
.render(
|
||||||
|
);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
28
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@antv/l7",
|
"name": "@antv/l7",
|
||||||
"version": "1.0.3",
|
"version": "1.2.0-beta.0",
|
||||||
"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",
|
||||||
|
@ -21,9 +21,9 @@
|
||||||
"author": "https://github.com/orgs/antvis/people",
|
"author": "https://github.com/orgs/antvis/people",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "~7.0.0",
|
"@babel/cli": "^7.4.3",
|
||||||
"@babel/core": "~7.0.0",
|
"@babel/core": "~7.4.3",
|
||||||
"@babel/preset-env": "~7.1.0",
|
"@babel/preset-env": "~7.4.3",
|
||||||
"babel-eslint": "~8.0.3",
|
"babel-eslint": "~8.0.3",
|
||||||
"babel-loader": "~8.0.0",
|
"babel-loader": "~8.0.0",
|
||||||
"babel-plugin-transform-remove-strict-mode": "~0.0.2",
|
"babel-plugin-transform-remove-strict-mode": "~0.0.2",
|
||||||
|
@ -48,6 +48,7 @@
|
||||||
"open": "~0.0.5",
|
"open": "~0.0.5",
|
||||||
"parseurl": "~1.3.2",
|
"parseurl": "~1.3.2",
|
||||||
"pre-commit": "~1.2.2",
|
"pre-commit": "~1.2.2",
|
||||||
|
"rollup": "^1.16.2",
|
||||||
"rollup-plugin-buble": "^0.19.6",
|
"rollup-plugin-buble": "^0.19.6",
|
||||||
"rollup-plugin-commonjs": "^9.2.1",
|
"rollup-plugin-commonjs": "^9.2.1",
|
||||||
"rollup-plugin-node-resolve": "^4.0.1",
|
"rollup-plugin-node-resolve": "^4.0.1",
|
||||||
|
@ -58,11 +59,14 @@
|
||||||
"torchjs": "~2.1.0",
|
"torchjs": "~2.1.0",
|
||||||
"uglify-js": "~3.1.10",
|
"uglify-js": "~3.1.10",
|
||||||
"webpack": "~4.29.6",
|
"webpack": "~4.29.6",
|
||||||
|
"webpack-cli": "^3.2.3",
|
||||||
"worker-loader": "^2.0.0"
|
"worker-loader": "^2.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build-dev": "rollup -c --environment BUILD:dev && npm run demos-web",
|
"build-dev": "rollup -c --environment BUILD:dev && npm run demos-web",
|
||||||
"watch-dev": "rollup -c --environment BUILD:dev --watch",
|
"watch-dev": "rollup -c --environment BUILD:dev --watch & npm run demos-web ",
|
||||||
|
"build-prod": "rollup -c --environment BUILD:production",
|
||||||
|
"build-prod-min": "rollup -c --environment BUILD:production,MINIFY:true",
|
||||||
"build": "webpack",
|
"build": "webpack",
|
||||||
"build-lib": "babel src --out-dir lib",
|
"build-lib": "babel src --out-dir lib",
|
||||||
"bundler": "electron ./bundler/app.js",
|
"bundler": "electron ./bundler/app.js",
|
||||||
|
@ -83,7 +87,7 @@
|
||||||
"mkdir-dist": "node ./bin/mkdir-dist.js",
|
"mkdir-dist": "node ./bin/mkdir-dist.js",
|
||||||
"prepublishOnly": "npm run build-lib && npm run dist",
|
"prepublishOnly": "npm run build-lib && npm run dist",
|
||||||
"screenshot": "node ./bin/screenshot.js",
|
"screenshot": "node ./bin/screenshot.js",
|
||||||
"start": "npm run dev",
|
"start": "npm run watch-dev",
|
||||||
"test": "torch --compile-opts ./.torch.compile.opts.js --compile --renderer --recursive test/unit",
|
"test": "torch --compile-opts ./.torch.compile.opts.js --compile --renderer --recursive test/unit",
|
||||||
"test-all": "npm run test && npm run test-bugs",
|
"test-all": "npm run test && npm run test-bugs",
|
||||||
"test-bugs": "torch --compile --renderer --recursive test/bugs",
|
"test-bugs": "torch --compile --renderer --recursive test/bugs",
|
||||||
|
@ -94,14 +98,17 @@
|
||||||
},
|
},
|
||||||
"pre-commit": {
|
"pre-commit": {
|
||||||
"run": [
|
"run": [
|
||||||
"lint"
|
"lint",
|
||||||
|
"test"
|
||||||
],
|
],
|
||||||
"silent": false
|
"silent": false
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@antv/g": "^3.1.3",
|
"@antv/g": "^3.1.3",
|
||||||
"@antv/util": "~1.2.5",
|
"@antv/geo-coord": "^1.0.8",
|
||||||
|
"@antv/util": "~2.0.1",
|
||||||
"@mapbox/tiny-sdf": "^1.1.0",
|
"@mapbox/tiny-sdf": "^1.1.0",
|
||||||
|
"@mapbox/vector-tile": "^1.3.1",
|
||||||
"@turf/bbox": "^6.0.1",
|
"@turf/bbox": "^6.0.1",
|
||||||
"@turf/clean-coords": "^6.0.1",
|
"@turf/clean-coords": "^6.0.1",
|
||||||
"@turf/invariant": "^6.1.2",
|
"@turf/invariant": "^6.1.2",
|
||||||
|
@ -111,10 +118,13 @@
|
||||||
"earcut": "^2.1.3",
|
"earcut": "^2.1.3",
|
||||||
"fecha": "^2.3.3",
|
"fecha": "^2.3.3",
|
||||||
"gl-matrix": "^2.4.1",
|
"gl-matrix": "^2.4.1",
|
||||||
|
"gl-vec2": "^1.3.0",
|
||||||
"lodash": "^4.17.5",
|
"lodash": "^4.17.5",
|
||||||
"polyline-normals": "^2.0.2",
|
"pbf": "^3.2.0",
|
||||||
|
"polyline-miter-util": "^1.0.1",
|
||||||
"rbush": "^2.0.2",
|
"rbush": "^2.0.2",
|
||||||
"simple-statistics": "^7.0.1",
|
"simple-statistics": "^7.0.1",
|
||||||
|
"supercluster": "^6.0.1",
|
||||||
"three": "^0.101.1",
|
"three": "^0.101.1",
|
||||||
"venn.js": "^0.2.20",
|
"venn.js": "^0.2.20",
|
||||||
"viewport-mercator-project": "^5.2.0",
|
"viewport-mercator-project": "^5.2.0",
|
||||||
|
|
|
@ -24,11 +24,11 @@ const config = [
|
||||||
indent: false,
|
indent: false,
|
||||||
chunkFileNames: 'shared.js'
|
chunkFileNames: 'shared.js'
|
||||||
},
|
},
|
||||||
experimentalCodeSplitting: true,
|
// experimentalCodeSplitting: true,
|
||||||
treeshake: production,
|
treeshake: false,
|
||||||
plugins: [
|
plugins: [
|
||||||
glsl(
|
glsl(
|
||||||
[ './src/geom/shader/*.glsl', './src/core/engine/picking/*.glsl' ],
|
[ './src/geom/shader/*.glsl', './src/core/engine/picking/*.glsl', './src/geom/shader/**/*.glsl' ],
|
||||||
production
|
production
|
||||||
),
|
),
|
||||||
minified ? terser() : false,
|
minified ? terser() : false,
|
||||||
|
|
|
@ -84,6 +84,9 @@ const ColorUtil = {
|
||||||
const rgba = this.toRGB(str);
|
const rgba = this.toRGB(str);
|
||||||
return rgba.map(v => v / 255);
|
return rgba.map(v => v / 255);
|
||||||
},
|
},
|
||||||
|
colorArray2RGBA(arr) {
|
||||||
|
return `rgba(${arr[0] * 255},${arr[1] * 255},${arr[2] * 255},${arr[3]})`;
|
||||||
|
},
|
||||||
color2RGBA(str) {
|
color2RGBA(str) {
|
||||||
return this.color2Arr(str);
|
return this.color2Arr(str);
|
||||||
},
|
},
|
||||||
|
|
|
@ -42,10 +42,11 @@ class Size extends Base {
|
||||||
_scaling(scale, v) {
|
_scaling(scale, v) {
|
||||||
if (scale.type === 'identity') {
|
if (scale.type === 'identity') {
|
||||||
return v;
|
return v;
|
||||||
} else if (scale.type === 'linear') {
|
}
|
||||||
const percent = scale.scale(v);
|
const percent = scale.scale(v);
|
||||||
return this.getLinearValue(percent);
|
return this.getLinearValue(percent);
|
||||||
}
|
|
||||||
|
// else if (scale.type === 'linear') {
|
||||||
}
|
}
|
||||||
|
|
||||||
getLinearValue(percent) {
|
getLinearValue(percent) {
|
||||||
|
|
|
@ -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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
import Util from '../../util';
|
||||||
|
import { updateObjecteUniform } from '../../util/object3d-util';
|
||||||
|
export default class BufferController {
|
||||||
|
constructor(cfg) {
|
||||||
|
// defs 列定义
|
||||||
|
Util.assign(this, cfg);
|
||||||
|
if (!this.mesh) this.mesh = this.layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateColorAttributes() {
|
||||||
|
const filterData = this.mesh.layerData;
|
||||||
|
const colorKey = {};
|
||||||
|
for (let e = 0; e < filterData.length; e++) {
|
||||||
|
const item = filterData[e];
|
||||||
|
colorKey[item.id] = item.color;
|
||||||
|
}
|
||||||
|
this.layer._activeIds = null; // 清空选中元素xwxw
|
||||||
|
const colorAttr = this.mesh.mesh.geometry.attributes.a_color;
|
||||||
|
const pickAttr = this.mesh.mesh.geometry.attributes.pickingId;
|
||||||
|
pickAttr.array.forEach((id, index) => {
|
||||||
|
let newId = Math.abs(id);
|
||||||
|
let item = null;
|
||||||
|
let color = null;
|
||||||
|
if (this.mesh.layerSource.data.featureKeys) { // hash数据映射
|
||||||
|
newId = this.mesh.layerSource.data.featureKeys[newId].index;
|
||||||
|
item = filterData[newId];
|
||||||
|
color = colorKey[item.id];
|
||||||
|
} else {
|
||||||
|
item = filterData[newId - 1];
|
||||||
|
color = colorKey[newId];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.hasOwnProperty('filter') && item.filter === false) {
|
||||||
|
colorAttr.array[index * 4 + 0] = 0;
|
||||||
|
colorAttr.array[index * 4 + 1] = 0;
|
||||||
|
colorAttr.array[index * 4 + 2] = 0;
|
||||||
|
colorAttr.array[index * 4 + 3] = 0;
|
||||||
|
pickAttr.array[index] = -id; // 通过Id数据过滤 id<0 不显示
|
||||||
|
} else {
|
||||||
|
colorAttr.array[index * 4 + 0] = color[0];
|
||||||
|
colorAttr.array[index * 4 + 1] = color[1];
|
||||||
|
colorAttr.array[index * 4 + 2] = color[2];
|
||||||
|
colorAttr.array[index * 4 + 3] = color[3];
|
||||||
|
pickAttr.array[index] = id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
colorAttr.needsUpdate = true;
|
||||||
|
pickAttr.needsUpdate = true;
|
||||||
|
}
|
||||||
|
_updateStyle(option) {
|
||||||
|
const newOption = { };
|
||||||
|
for (const key in option) {
|
||||||
|
newOption['u_' + key] = option[key];
|
||||||
|
}
|
||||||
|
updateObjecteUniform(this.mesh._object3D, newOption);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import Util from '../../util';
|
||||||
|
export default class EventContoller {
|
||||||
|
constructor(cfg) {
|
||||||
|
Util.assign(this, cfg);
|
||||||
|
}
|
||||||
|
_init() {
|
||||||
|
this.layer.scene.on('pick-' + this.layer.layerId, e => {
|
||||||
|
let { featureId, point2d, type } = e;
|
||||||
|
if (featureId < 0 && this._activeIds !== null) {
|
||||||
|
type = 'mouseleave';
|
||||||
|
}
|
||||||
|
this._activeIds = featureId;
|
||||||
|
// TODO 瓦片图层获取选中数据信息
|
||||||
|
const lnglat = this.layer.scene.containerToLngLat(point2d);
|
||||||
|
const { feature, style } = this.layer.getSelectFeature(featureId, lnglat);
|
||||||
|
// const style = this.layerData[featureId - 1];
|
||||||
|
const target = {
|
||||||
|
featureId,
|
||||||
|
feature,
|
||||||
|
style,
|
||||||
|
pixel: point2d,
|
||||||
|
type,
|
||||||
|
lnglat: { lng: lnglat.lng, lat: lnglat.lat }
|
||||||
|
};
|
||||||
|
if (featureId >= 0 || this._activeIds >= 0) { // 拾取到元素,或者离开元素
|
||||||
|
this.layer.emit(type, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_initMapEvent() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,14 @@
|
||||||
import Scale from './scale';
|
import Scale from './scale';
|
||||||
|
import Mapping from './mapping';
|
||||||
|
import Picking from './pick';
|
||||||
|
import Interaction from './interaction';
|
||||||
|
import Event from './event';
|
||||||
|
import Buffer from './buffer';
|
||||||
export default {
|
export default {
|
||||||
Scale
|
Scale,
|
||||||
|
Mapping,
|
||||||
|
Picking,
|
||||||
|
Interaction,
|
||||||
|
Event,
|
||||||
|
Buffer
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import Util from '../../util';
|
||||||
|
import { getInteraction } from '../../interaction/index';
|
||||||
|
export default class InteractionController {
|
||||||
|
constructor(cfg) {
|
||||||
|
// defs 列定义
|
||||||
|
Util.assign(this, cfg);
|
||||||
|
}
|
||||||
|
// interaction 方法
|
||||||
|
clearAllInteractions() {
|
||||||
|
const interactions = this.layer.get('interactions');
|
||||||
|
Util.each(interactions, (interaction, key) => {
|
||||||
|
interaction.destory();
|
||||||
|
delete interactions[key];
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
clearInteraction(type) {
|
||||||
|
const interactions = this.layer.get('interactions');
|
||||||
|
if (interactions[type]) {
|
||||||
|
interactions[type].destory();
|
||||||
|
delete interactions[type];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
addInteraction(type, cfg = {}) {
|
||||||
|
cfg.layer = this.layer;
|
||||||
|
const Ctor = getInteraction(type);
|
||||||
|
const interaction = new Ctor(cfg);
|
||||||
|
this._setInteraction(type, interaction);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
_setInteraction(type, interaction) {
|
||||||
|
const interactions = this.layer.get('interactions');
|
||||||
|
if (interactions[type]) {
|
||||||
|
interactions[type].destory();
|
||||||
|
}
|
||||||
|
interactions[type] = interaction;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
|
|
||||||
export class layerControl {
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
|
|
||||||
import { getMap } from '../../map';
|
|
||||||
import Base from '../base';
|
|
||||||
export default class MapContorller extends Base {
|
|
||||||
constructor(cfg, engine, scene) {
|
|
||||||
super(cfg);
|
|
||||||
this._engine = engine;
|
|
||||||
this.scene = scene;
|
|
||||||
}
|
|
||||||
_init() {
|
|
||||||
const mapType = this.get('mapType');
|
|
||||||
const mapCfg = this.get('mapCfg');
|
|
||||||
this.map = new getMap(mapType)(mapCfg);
|
|
||||||
this.map('mapLoad', this._mapload.bind(this));
|
|
||||||
}
|
|
||||||
_mapload() {
|
|
||||||
this.map.asyncCamera(this._engine);
|
|
||||||
this.emit('loaded');
|
|
||||||
}
|
|
||||||
_bindMapMethod() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
import Util from '../../util';
|
||||||
|
import Global from '../../global';
|
||||||
|
import ScaleController from './scale';
|
||||||
|
import Attr from '../../attr/index';
|
||||||
|
export default class Mapping {
|
||||||
|
/** 初始化mapping
|
||||||
|
* 初始化mapping
|
||||||
|
* @param {*} cfg 配置
|
||||||
|
* @param {*} cfg.layer layer对象
|
||||||
|
* @param {*} cfg.mesh mesh对象
|
||||||
|
*/
|
||||||
|
constructor(cfg) {
|
||||||
|
Util.assign(this, cfg);
|
||||||
|
if (!this.mesh) this.mesh = this.layer;
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
_init() {
|
||||||
|
this._initControllers();
|
||||||
|
this._initTileAttrs();
|
||||||
|
this._mapping();
|
||||||
|
}
|
||||||
|
update() {
|
||||||
|
this.mesh.set('scales', {});
|
||||||
|
this._initTileAttrs();
|
||||||
|
this._updateMaping();
|
||||||
|
}
|
||||||
|
_initControllers() {
|
||||||
|
const scalesOption = this.layer.get('scaleOptions');
|
||||||
|
const scaleController = new ScaleController({
|
||||||
|
defs: {
|
||||||
|
...scalesOption
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.mesh.set('scaleController', scaleController);
|
||||||
|
}
|
||||||
|
_createScale(field) {
|
||||||
|
const scales = this.mesh.get('scales');
|
||||||
|
this._initControllers(); // scale更新
|
||||||
|
let scale = scales[field];
|
||||||
|
if (!scale) {
|
||||||
|
scale = this.createScale(field);
|
||||||
|
scales[field] = scale;
|
||||||
|
}
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
createScale(field) {
|
||||||
|
const data = this.mesh.layerSource.data.dataArray;
|
||||||
|
const scales = this.mesh.get('scales');
|
||||||
|
let scale = scales[field];
|
||||||
|
const scaleController = this.mesh.get('scaleController');
|
||||||
|
if (!scale) {
|
||||||
|
scale = scaleController.createScale(field, data);
|
||||||
|
scales[field] = scale;
|
||||||
|
}
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
// 获取属性映射的值
|
||||||
|
_getAttrValues(attr, record) {
|
||||||
|
const scales = attr.scales;
|
||||||
|
const params = [];
|
||||||
|
for (let i = 0; i < scales.length; i++) {
|
||||||
|
const scale = scales[i];
|
||||||
|
const field = scale.field;
|
||||||
|
if (scale.type === 'identity') {
|
||||||
|
params.push(scale.value);
|
||||||
|
} else {
|
||||||
|
params.push(record[field]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const indexZoom = params.indexOf('zoom');
|
||||||
|
indexZoom !== -1 ? params[indexZoom] = attr.zoom : null;
|
||||||
|
const values = attr.mapping(...params);
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
_mapping() {
|
||||||
|
const attrs = this.mesh.get('attrs');
|
||||||
|
const mappedData = [];
|
||||||
|
const data = this.mesh.layerSource.data.dataArray;
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const record = data[i];
|
||||||
|
const newRecord = {};
|
||||||
|
newRecord.id = data[i]._id;
|
||||||
|
for (const k in attrs) {
|
||||||
|
if (attrs.hasOwnProperty(k)) {
|
||||||
|
const attr = attrs[k];
|
||||||
|
const names = attr.names;
|
||||||
|
const values = this._getAttrValues(attr, record);
|
||||||
|
if (names.length > 1) { // position 之类的生成多个字段的属性
|
||||||
|
for (let j = 0; j < values.length; j++) {
|
||||||
|
const val = values[j];
|
||||||
|
const name = names[j];
|
||||||
|
newRecord[name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newRecord[names[0]] = values.length === 1 ? values[0] : values;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newRecord.coordinates = record.coordinates;
|
||||||
|
mappedData.push(newRecord);
|
||||||
|
}
|
||||||
|
// 通过透明度过滤数据
|
||||||
|
if (attrs.hasOwnProperty('filter')) {
|
||||||
|
mappedData.forEach(item => {
|
||||||
|
if (item.filter === false) {
|
||||||
|
(item.color[3] = 0);
|
||||||
|
item.id = -item.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.mesh.layerData = mappedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新数据maping
|
||||||
|
* @param {*} layerSource 数据源
|
||||||
|
* @param {*} layer map
|
||||||
|
*/
|
||||||
|
_updateMaping() {
|
||||||
|
const attrs = this.mesh.get('attrs');
|
||||||
|
|
||||||
|
const data = this.mesh.layerSource.data.dataArray;
|
||||||
|
const layerData = this.mesh.layerData;
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const record = data[i];
|
||||||
|
for (const attrName in attrs) {
|
||||||
|
if (attrs.hasOwnProperty(attrName) && attrs[attrName].neadUpdate) {
|
||||||
|
const attr = attrs[attrName];
|
||||||
|
const names = attr.names;
|
||||||
|
const values = this._getAttrValues(attr, record);
|
||||||
|
if (names.length > 1) { // position 之类的生成多个字段的属性
|
||||||
|
for (let j = 0; j < values.length; j++) {
|
||||||
|
const val = values[j];
|
||||||
|
const name = names[j];
|
||||||
|
layerData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
layerData[i][names[0]] = values.length === 1 ? values[0] : values;
|
||||||
|
|
||||||
|
}
|
||||||
|
attr.neadUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_initTileAttrs() {
|
||||||
|
const attrOptions = this.layer.get('attrOptions');
|
||||||
|
for (const type in attrOptions) {
|
||||||
|
if (attrOptions.hasOwnProperty(type)) {
|
||||||
|
this._updateTileAttr(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_updateTileAttr(type) {
|
||||||
|
const self = this;
|
||||||
|
const attrs = this.mesh.get('attrs');
|
||||||
|
const attrOptions = this.layer.get('attrOptions');
|
||||||
|
const option = attrOptions[type];
|
||||||
|
option.neadUpdate = true;
|
||||||
|
const className = Util.upperFirst(type);
|
||||||
|
const fields = this._parseFields(option.field);
|
||||||
|
const scales = [];
|
||||||
|
for (let i = 0; i < fields.length; i++) {
|
||||||
|
const field = fields[i];
|
||||||
|
const scale = self._createScale(field);
|
||||||
|
|
||||||
|
if (type === 'color' && Util.isNil(option.values)) { // 设置 color 的默认色值
|
||||||
|
option.values = Global.colors;
|
||||||
|
}
|
||||||
|
scales.push(scale);
|
||||||
|
}
|
||||||
|
option.scales = scales;
|
||||||
|
const attr = new Attr[className](option);
|
||||||
|
attrs[type] = attr;
|
||||||
|
}
|
||||||
|
_parseFields(field) {
|
||||||
|
if (Util.isArray(field)) {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
if (Util.isString(field)) {
|
||||||
|
return field.split('*');
|
||||||
|
}
|
||||||
|
return [ field ];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
import Util from '../../util';
|
||||||
|
import * as THREE from '../three';
|
||||||
|
import pickingFragmentShader from '../engine/picking/picking_frag.glsl';
|
||||||
|
import { updateObjecteUniform, destoryObject } from '../../util/object3d-util';
|
||||||
|
export default class PickContoller {
|
||||||
|
constructor(cfg) {
|
||||||
|
Util.assign(this, cfg);
|
||||||
|
this.pickObject3D = new THREE.Object3D();
|
||||||
|
this.addToPicking(this.pickObject3D);
|
||||||
|
}
|
||||||
|
getPickingId() {
|
||||||
|
return this.layer.scene._engine._picking.getNextId();
|
||||||
|
}
|
||||||
|
addToPicking(object) {
|
||||||
|
object.name = this.layer.layerId;
|
||||||
|
this.layer.scene._engine._picking.add(object);
|
||||||
|
}
|
||||||
|
removePickingObject(object) {
|
||||||
|
this.layer.scene._engine._picking.remove(object);
|
||||||
|
}
|
||||||
|
removePickingMesh(mesh) {
|
||||||
|
this.pickObject3D.remove(mesh);
|
||||||
|
destoryObject(mesh);
|
||||||
|
}
|
||||||
|
removePickMeshByName(name) {
|
||||||
|
for (let i = 0; i < this.pickObject3D.children.length; i++) {
|
||||||
|
if (this.pickObject3D.children[i].name === name) {
|
||||||
|
this.removePickingMesh(this.pickObject3D.children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeAllMesh() {
|
||||||
|
this.pickObject3D.children.forEach(element => {
|
||||||
|
|
||||||
|
this.pickObject3D.remove(element);
|
||||||
|
destoryObject(element);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
addPickMesh(mesh) {
|
||||||
|
const pickmaterial = mesh.material.clone();
|
||||||
|
pickmaterial.fragmentShader = pickingFragmentShader;
|
||||||
|
const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial);
|
||||||
|
pickingMesh.name = mesh.name;
|
||||||
|
pickingMesh.onBeforeRender = () => {
|
||||||
|
const zoom = this.layer.scene.getZoom();
|
||||||
|
updateObjecteUniform(pickingMesh, { u_zoom: zoom });
|
||||||
|
};
|
||||||
|
this.pickObject3D.add(pickingMesh);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
// jscs:disable
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import * as THREE from '../three';
|
||||||
|
import CopyShader from './copy-shader';
|
||||||
|
import ShaderPass from './shader-pass';
|
||||||
|
import MaskPass, {ClearMaskPass} from './mask-pass';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author alteredq / http://alteredqualia.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
var EffectComposer = function ( renderer, renderTarget ) {
|
||||||
|
|
||||||
|
this.renderer = renderer;
|
||||||
|
|
||||||
|
if ( renderTarget === undefined ) {
|
||||||
|
|
||||||
|
var pixelRatio = renderer.getPixelRatio();
|
||||||
|
|
||||||
|
var width = Math.floor( renderer.context.canvas.width / pixelRatio ) || 1;
|
||||||
|
var height = Math.floor( renderer.context.canvas.height / pixelRatio ) || 1;
|
||||||
|
var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat, stencilBuffer: false };
|
||||||
|
|
||||||
|
renderTarget = new THREE.WebGLRenderTarget( width, height, parameters );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderTarget1 = renderTarget;
|
||||||
|
this.renderTarget2 = renderTarget.clone();
|
||||||
|
|
||||||
|
this.writeBuffer = this.renderTarget1;
|
||||||
|
this.readBuffer = this.renderTarget2;
|
||||||
|
|
||||||
|
this.passes = [];
|
||||||
|
|
||||||
|
if ( CopyShader === undefined )
|
||||||
|
console.error( "EffectComposer relies on THREE.CopyShader" );
|
||||||
|
|
||||||
|
this.copyPass = new ShaderPass( CopyShader );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
EffectComposer.prototype = {
|
||||||
|
|
||||||
|
swapBuffers: function() {
|
||||||
|
|
||||||
|
var tmp = this.readBuffer;
|
||||||
|
this.readBuffer = this.writeBuffer;
|
||||||
|
this.writeBuffer = tmp;
|
||||||
|
|
||||||
|
},
|
||||||
|
visible:true,
|
||||||
|
type:'composer',
|
||||||
|
addPass: function ( pass ) {
|
||||||
|
|
||||||
|
this.passes.push( pass );
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
insertPass: function ( pass, index ) {
|
||||||
|
|
||||||
|
this.passes.splice( index, 0, pass );
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function ( delta ) {
|
||||||
|
|
||||||
|
this.writeBuffer = this.renderTarget1;
|
||||||
|
this.readBuffer = this.renderTarget2;
|
||||||
|
|
||||||
|
var maskActive = false;
|
||||||
|
|
||||||
|
var pass, i, il = this.passes.length;
|
||||||
|
for ( i = 0; i < il; i ++ ) {
|
||||||
|
|
||||||
|
pass = this.passes[ i ];
|
||||||
|
|
||||||
|
if ( ! pass.enabled ) continue;
|
||||||
|
|
||||||
|
pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive );
|
||||||
|
|
||||||
|
if ( pass.needsSwap ) {
|
||||||
|
|
||||||
|
if ( maskActive ) {
|
||||||
|
|
||||||
|
var context = this.renderer.context;
|
||||||
|
|
||||||
|
context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
|
||||||
|
|
||||||
|
this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta );
|
||||||
|
|
||||||
|
context.stencilFunc( context.EQUAL, 1, 0xffffffff );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.swapBuffers();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pass instanceof MaskPass ) {
|
||||||
|
|
||||||
|
maskActive = true;
|
||||||
|
|
||||||
|
} else if ( pass instanceof ClearMaskPass ) {
|
||||||
|
|
||||||
|
maskActive = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function ( renderTarget ) {
|
||||||
|
|
||||||
|
if ( renderTarget === undefined ) {
|
||||||
|
|
||||||
|
renderTarget = this.renderTarget1.clone();
|
||||||
|
|
||||||
|
var pixelRatio = this.renderer.getPixelRatio();
|
||||||
|
|
||||||
|
renderTarget.setSize(
|
||||||
|
Math.floor( this.renderer.context.canvas.width / pixelRatio ),
|
||||||
|
Math.floor( this.renderer.context.canvas.height / pixelRatio )
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderTarget1.dispose();
|
||||||
|
this.renderTarget1 = renderTarget;
|
||||||
|
this.renderTarget2.dispose();
|
||||||
|
this.renderTarget2 = renderTarget.clone();
|
||||||
|
|
||||||
|
this.writeBuffer = this.renderTarget1;
|
||||||
|
this.readBuffer = this.renderTarget2;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
setSize: function ( width, height ) {
|
||||||
|
|
||||||
|
this.renderTarget1.setSize( width, height );
|
||||||
|
this.renderTarget2.setSize( width, height );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EffectComposer;
|
|
@ -0,0 +1,53 @@
|
||||||
|
// jscs:disable
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import * as THREE from '../three';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author alteredq / http://alteredqualia.com/
|
||||||
|
*
|
||||||
|
* Full-screen textured quad shader
|
||||||
|
*/
|
||||||
|
|
||||||
|
var CopyShader = {
|
||||||
|
|
||||||
|
uniforms: {
|
||||||
|
|
||||||
|
"tDiffuse": { type: "t", value: null },
|
||||||
|
"opacity": { type: "f", value: 1.0 }
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
vertexShader: [
|
||||||
|
|
||||||
|
"varying vec2 vUv;",
|
||||||
|
|
||||||
|
"void main() {",
|
||||||
|
|
||||||
|
"vUv = uv;",
|
||||||
|
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
|
||||||
|
|
||||||
|
"}"
|
||||||
|
|
||||||
|
].join( "\n" ),
|
||||||
|
|
||||||
|
fragmentShader: [
|
||||||
|
|
||||||
|
"uniform float opacity;",
|
||||||
|
|
||||||
|
"uniform sampler2D tDiffuse;",
|
||||||
|
|
||||||
|
"varying vec2 vUv;",
|
||||||
|
|
||||||
|
"void main() {",
|
||||||
|
|
||||||
|
"vec4 texel = texture2D( tDiffuse, vUv );",
|
||||||
|
"gl_FragColor = opacity * texel;",
|
||||||
|
|
||||||
|
"}"
|
||||||
|
|
||||||
|
].join( "\n" )
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CopyShader;
|
|
@ -0,0 +1,21 @@
|
||||||
|
import EffectComposer from './composer';
|
||||||
|
|
||||||
|
export default function(renderer, container) {
|
||||||
|
const composer = new EffectComposer(renderer);
|
||||||
|
|
||||||
|
const updateSize = function() {
|
||||||
|
// TODO: Re-enable this when perf issues can be solved
|
||||||
|
//
|
||||||
|
// Rendering double the resolution of the screen can be really slow
|
||||||
|
// var pixelRatio = window.devicePixelRatio;
|
||||||
|
const pixelRatio = 1;
|
||||||
|
|
||||||
|
composer.setSize(container.clientWidth * pixelRatio, container.clientHeight * pixelRatio);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('resize', updateSize, false);
|
||||||
|
updateSize();
|
||||||
|
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
|
@ -10,26 +10,31 @@ export default class Engine extends EventEmitter {
|
||||||
this._scene = Scene;
|
this._scene = Scene;
|
||||||
this._camera = new Camera(container).camera;
|
this._camera = new Camera(container).camera;
|
||||||
this._renderer = new Renderer(container).renderer;
|
this._renderer = new Renderer(container).renderer;
|
||||||
this._world = world;
|
this._world = world;// 地图场景实例
|
||||||
// for MapBox
|
// for MapBox
|
||||||
this.world = new THREE.Group();
|
this.world = new THREE.Group();
|
||||||
this._scene.add(this.world);
|
this._scene.add(this.world);
|
||||||
this._picking = Picking(this._world, this._renderer, this._camera, this._scene);
|
this._picking = Picking(this._world, this._renderer, this._camera);
|
||||||
this.clock = new THREE.Clock();
|
this.clock = new THREE.Clock();
|
||||||
|
this.composerLayers = [];
|
||||||
}
|
}
|
||||||
_initPostProcessing() {
|
_initPostProcessing() {
|
||||||
|
this.composerLayers.forEach(layer => {
|
||||||
|
layer.visible && layer.render();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
update() {
|
update() {
|
||||||
|
this._renderer.clear();
|
||||||
this._renderer.render(this._scene, this._camera);
|
this._renderer.render(this._scene, this._camera);
|
||||||
|
this._initPostProcessing();
|
||||||
}
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
|
}
|
||||||
|
// 渲染第三方Scene对象
|
||||||
|
renderScene(scene) {
|
||||||
|
this._renderer.render(scene, this._camera);
|
||||||
}
|
}
|
||||||
run() {
|
run() {
|
||||||
|
|
||||||
this.update();
|
this.update();
|
||||||
this.engineID = requestAnimationFrame(this.run.bind(this));
|
this.engineID = requestAnimationFrame(this.run.bind(this));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
// jscs:disable
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import * as THREE from '../three';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author alteredq / http://alteredqualia.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
var MaskPass = function ( scene, camera ) {
|
||||||
|
|
||||||
|
this.scene = scene;
|
||||||
|
this.camera = camera;
|
||||||
|
|
||||||
|
this.enabled = true;
|
||||||
|
this.clear = true;
|
||||||
|
this.needsSwap = false;
|
||||||
|
|
||||||
|
this.inverse = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
MaskPass.prototype = {
|
||||||
|
|
||||||
|
render: function ( renderer, writeBuffer, readBuffer, delta ) {
|
||||||
|
|
||||||
|
var context = renderer.context;
|
||||||
|
|
||||||
|
// don't update color or depth
|
||||||
|
|
||||||
|
context.colorMask( false, false, false, false );
|
||||||
|
context.depthMask( false );
|
||||||
|
|
||||||
|
// set up stencil
|
||||||
|
|
||||||
|
var writeValue, clearValue;
|
||||||
|
|
||||||
|
if ( this.inverse ) {
|
||||||
|
|
||||||
|
writeValue = 0;
|
||||||
|
clearValue = 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
writeValue = 1;
|
||||||
|
clearValue = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
context.enable( context.STENCIL_TEST );
|
||||||
|
context.stencilOp( context.REPLACE, context.REPLACE, context.REPLACE );
|
||||||
|
context.stencilFunc( context.ALWAYS, writeValue, 0xffffffff );
|
||||||
|
context.clearStencil( clearValue );
|
||||||
|
|
||||||
|
// draw into the stencil buffer
|
||||||
|
|
||||||
|
renderer.render( this.scene, this.camera, readBuffer, this.clear );
|
||||||
|
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
|
||||||
|
|
||||||
|
// re-enable update of color and depth
|
||||||
|
|
||||||
|
context.colorMask( true, true, true, true );
|
||||||
|
context.depthMask( true );
|
||||||
|
|
||||||
|
// only render where stencil is set to 1
|
||||||
|
|
||||||
|
context.stencilFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
|
||||||
|
context.stencilOp( context.KEEP, context.KEEP, context.KEEP );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var ClearMaskPass = function () {
|
||||||
|
|
||||||
|
this.enabled = true;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
ClearMaskPass.prototype = {
|
||||||
|
|
||||||
|
render: function ( renderer, writeBuffer, readBuffer, delta ) {
|
||||||
|
|
||||||
|
var context = renderer.context;
|
||||||
|
|
||||||
|
context.disable( context.STENCIL_TEST );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MaskPass;
|
||||||
|
export {ClearMaskPass as ClearMaskPass};
|
|
@ -3,13 +3,10 @@ import * as THREE from '../../three';
|
||||||
let nextId = 1;
|
let nextId = 1;
|
||||||
|
|
||||||
class Picking {
|
class Picking {
|
||||||
constructor(world, renderer, camera, scene) {
|
constructor(world, renderer, camera) {
|
||||||
this._world = world;
|
this._world = world;
|
||||||
this._renderer = renderer;
|
this._renderer = renderer;
|
||||||
this._camera = camera;
|
this._camera = camera;
|
||||||
this._raycaster = new THREE.Raycaster();
|
|
||||||
this.scene = scene;
|
|
||||||
this._raycaster.linePrecision = 10;
|
|
||||||
this._pickingScene = PickingScene;
|
this._pickingScene = PickingScene;
|
||||||
this.world = new THREE.Group();
|
this.world = new THREE.Group();
|
||||||
this._pickingScene.add(this.world);
|
this._pickingScene.add(this.world);
|
||||||
|
@ -49,13 +46,11 @@ class Picking {
|
||||||
this._height = size.height;
|
this._height = size.height;
|
||||||
this._pickingTexture.setSize(this._width, this._height);
|
this._pickingTexture.setSize(this._width, this._height);
|
||||||
this._pixelBuffer = new Uint8Array(4 * this._width * this._height);
|
this._pixelBuffer = new Uint8Array(4 * this._width * this._height);
|
||||||
|
|
||||||
this._needUpdate = true;
|
this._needUpdate = true;
|
||||||
}
|
}
|
||||||
_update(point) {
|
_update(point) {
|
||||||
|
|
||||||
const texture = this._pickingTexture;
|
const texture = this._pickingTexture;
|
||||||
this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
|
this._renderer.render(this._pickingScene, this._camera, texture);
|
||||||
this.pixelBuffer = new Uint8Array(4);
|
this.pixelBuffer = new Uint8Array(4);
|
||||||
this._renderer.readRenderTargetPixels(texture, point.x, this._height - point.y, 1, 1, this.pixelBuffer);
|
this._renderer.readRenderTargetPixels(texture, point.x, this._height - point.y, 1, 1, this.pixelBuffer);
|
||||||
|
|
||||||
|
@ -66,8 +61,23 @@ class Picking {
|
||||||
index === id ? object.visible = true : object.visible = false;
|
index === id ? object.visible = true : object.visible = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
_layerIsVisable(object) {
|
||||||
|
const layers = this._world.getLayers();
|
||||||
|
let isVisable = false;
|
||||||
|
for (let i = 0; i < layers.length; i++) {
|
||||||
|
const layer = layers[i];
|
||||||
|
if (object.name === layer.layerId) {
|
||||||
|
isVisable = layer.get('visible');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isVisable;
|
||||||
|
}
|
||||||
_pickAllObject(point, normalisedPoint) {
|
_pickAllObject(point, normalisedPoint) {
|
||||||
this.world.children.forEach((object, index) => {
|
this.world.children.forEach((object, index) => {
|
||||||
|
if (!this._layerIsVisable(object)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this._filterObject(index);
|
this._filterObject(index);
|
||||||
const item = this._pick(point, normalisedPoint, object.name);
|
const item = this._pick(point, normalisedPoint, object.name);
|
||||||
item.type = point.type;
|
item.type = point.type;
|
||||||
|
@ -76,9 +86,9 @@ class Picking {
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_updateRender() {
|
// _updateRender() {
|
||||||
this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
|
// this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
|
||||||
}
|
// }
|
||||||
|
|
||||||
_pick(point, normalisedPoint, layerId) {
|
_pick(point, normalisedPoint, layerId) {
|
||||||
this._update(point);
|
this._update(point);
|
||||||
|
@ -87,21 +97,11 @@ class Picking {
|
||||||
id = -999;
|
id = -999;
|
||||||
// return;
|
// return;
|
||||||
}
|
}
|
||||||
this._raycaster.setFromCamera(normalisedPoint, this._camera);
|
|
||||||
|
|
||||||
const intersects = this._raycaster.intersectObjects(this._pickingScene.children, true);
|
|
||||||
const _point2d = { x: point.x, y: point.y };
|
const _point2d = { x: point.x, y: point.y };
|
||||||
|
|
||||||
let _point3d;
|
|
||||||
if (intersects.length > 0) {
|
|
||||||
_point3d = intersects[0].point;
|
|
||||||
}
|
|
||||||
const item = {
|
const item = {
|
||||||
layerId,
|
layerId,
|
||||||
featureId: id - 1,
|
featureId: id,
|
||||||
point2d: _point2d,
|
point2d: _point2d
|
||||||
point3d: _point3d,
|
|
||||||
intersects
|
|
||||||
};
|
};
|
||||||
return item;
|
return item;
|
||||||
|
|
||||||
|
@ -135,8 +135,6 @@ class Picking {
|
||||||
this._world._container.removeEventListener(event[0], event[1], false);
|
this._world._container.removeEventListener(event[0], event[1], false);
|
||||||
});
|
});
|
||||||
|
|
||||||
this._world.off('move', this._onWorldMove);
|
|
||||||
|
|
||||||
if (this._pickingScene.children) {
|
if (this._pickingScene.children) {
|
||||||
// Remove everything else in the layer
|
// Remove everything else in the layer
|
||||||
let child;
|
let child;
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import Material from '../../../geom/material/material';
|
import Material from '../../../geom/material/material';
|
||||||
import picking_frag from './picking_frag.glsl';
|
import picking_frag from './picking_frag.glsl';
|
||||||
import picking_vert from './picking_vert.glsl';
|
// import picking_vert from './picking_vert.glsl';
|
||||||
|
|
||||||
export default function PickingMaterial(options) {
|
export default function PickingMaterial(options) {
|
||||||
const material = new Material({
|
const material = new Material({
|
||||||
uniforms: {
|
uniforms: {
|
||||||
u_zoom: { value: options.u_zoom || 1 }
|
u_zoom: { value: options.u_zoom || 1 }
|
||||||
},
|
},
|
||||||
vertexShader: picking_vert,
|
vertexShader: options.vs,
|
||||||
fragmentShader: picking_frag,
|
fragmentShader: picking_frag,
|
||||||
transparent: false
|
transparent: false
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
// jscs:disable
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import * as THREE from '../three';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author alteredq / http://alteredqualia.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
var RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) {
|
||||||
|
|
||||||
|
this.scene = scene;
|
||||||
|
this.camera = camera;
|
||||||
|
|
||||||
|
this.overrideMaterial = overrideMaterial;
|
||||||
|
|
||||||
|
this.clearColor = clearColor;
|
||||||
|
this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 1;
|
||||||
|
|
||||||
|
this.oldClearColor = new THREE.Color();
|
||||||
|
this.oldClearAlpha = 1;
|
||||||
|
|
||||||
|
this.enabled = true;
|
||||||
|
this.clear = false;
|
||||||
|
this.needsSwap = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
RenderPass.prototype = {
|
||||||
|
|
||||||
|
render: function ( renderer, writeBuffer, readBuffer, delta ) {
|
||||||
|
|
||||||
|
this.scene.overrideMaterial = this.overrideMaterial;
|
||||||
|
if ( this.clearColor ) {
|
||||||
|
|
||||||
|
this.oldClearColor.copy( renderer.getClearColor() );
|
||||||
|
this.oldClearAlpha = renderer.getClearAlpha();
|
||||||
|
|
||||||
|
renderer.setClearColor( this.clearColor, this.clearAlpha );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.render( this.scene, this.camera, readBuffer, this.clear );
|
||||||
|
|
||||||
|
|
||||||
|
if ( this.clearColor ) {
|
||||||
|
|
||||||
|
renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scene.overrideMaterial = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RenderPass;
|
|
@ -9,7 +9,8 @@ export default class Renderer {
|
||||||
initRender() {
|
initRender() {
|
||||||
this.renderer = new THREE.WebGLRenderer({
|
this.renderer = new THREE.WebGLRenderer({
|
||||||
antialias: true,
|
antialias: true,
|
||||||
alpha: true
|
alpha: true,
|
||||||
|
autoClear: false
|
||||||
});
|
});
|
||||||
this.renderer.setClearColor(0xff0000, 0.0);
|
this.renderer.setClearColor(0xff0000, 0.0);
|
||||||
this.pixelRatio = window.devicePixelRatio;
|
this.pixelRatio = window.devicePixelRatio;
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
import * as THREE from '../three';
|
|
||||||
|
|
||||||
export class RenderPass {
|
|
||||||
constructor(cfg) {
|
|
||||||
this.scene;
|
|
||||||
this.camera = cfg.camera;
|
|
||||||
this.renderer = cfg.renderer;
|
|
||||||
this.clearColor = cfg.clear.clearColor;
|
|
||||||
this.clearAlpha = cfg.clear.clearAlpha;
|
|
||||||
this._init(cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
_init() {
|
|
||||||
this.scene = new THREE.Scene();
|
|
||||||
const parameters = { minFilter: THREE.NearestFilter,
|
|
||||||
magFilter: THREE.NearestFilter,
|
|
||||||
format: THREE.RGBAFormat,
|
|
||||||
stencilBuffer: false,
|
|
||||||
depthBuffer: false
|
|
||||||
};
|
|
||||||
const size = this.renderer.getSize();
|
|
||||||
this.pass = new THREE.WebGLRenderTarget(size.width, size.height, parameters);
|
|
||||||
this.originClearColor = this.renderer.getClearColor();
|
|
||||||
this.originClearAlpha = this.renderer.getClearAlpha();
|
|
||||||
this.texture = this.pass.texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
add(mesh) {
|
|
||||||
this.scene.add(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(mesh) {
|
|
||||||
this.scene.remove(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
this.renderer.setClearColor(this.clearColor, this.clearAlpha);
|
|
||||||
this.renderer.render(this.scene, this.camera, this.pass, true); // this.pass,true
|
|
||||||
this.renderer.setClearColor(this.clearColor, this.clearAlpha);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
// jscs:disable
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import * as THREE from '../three';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author alteredq / http://alteredqualia.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
var ShaderPass = function( shader, textureID ) {
|
||||||
|
|
||||||
|
this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse";
|
||||||
|
|
||||||
|
if ( shader instanceof THREE.ShaderMaterial ) {
|
||||||
|
|
||||||
|
this.uniforms = shader.uniforms;
|
||||||
|
|
||||||
|
this.material = shader;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if ( shader ) {
|
||||||
|
|
||||||
|
this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
|
||||||
|
|
||||||
|
this.material = new THREE.ShaderMaterial( {
|
||||||
|
|
||||||
|
defines: shader.defines || {},
|
||||||
|
uniforms: this.uniforms,
|
||||||
|
vertexShader: shader.vertexShader,
|
||||||
|
fragmentShader: shader.fragmentShader
|
||||||
|
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderToScreen = false;
|
||||||
|
|
||||||
|
this.enabled = true;
|
||||||
|
this.needsSwap = true;
|
||||||
|
this.clear = true;
|
||||||
|
|
||||||
|
|
||||||
|
this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
|
||||||
|
this.scene = new THREE.Scene();
|
||||||
|
|
||||||
|
this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
|
||||||
|
this.scene.add( this.quad );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
ShaderPass.prototype = {
|
||||||
|
|
||||||
|
render: function( renderer, writeBuffer, readBuffer, delta ) {
|
||||||
|
if ( this.uniforms[ this.textureID ] ) {
|
||||||
|
this.uniforms[ this.textureID ].value = readBuffer.texture;
|
||||||
|
|
||||||
|
}
|
||||||
|
renderer.autoClear = false;
|
||||||
|
this.quad.material = this.material;
|
||||||
|
|
||||||
|
if ( this.renderToScreen ) {
|
||||||
|
renderer.render( this.scene, this.camera );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
|
||||||
|
|
||||||
|
}
|
||||||
|
renderer.autoClear = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ShaderPass;
|
|
@ -28,14 +28,11 @@ export default class LoadImage extends EventEmitter {
|
||||||
if (typeof opt === 'string') {
|
if (typeof opt === 'string') {
|
||||||
getImage({ url: opt }, (err, img) => {
|
getImage({ url: opt }, (err, img) => {
|
||||||
img.id = id;
|
img.id = id;
|
||||||
|
|
||||||
this.images.push(img);
|
this.images.push(img);
|
||||||
this.ctx.drawImage(img, x, y, this.imageWidth, this.imageWidth);
|
this.ctx.drawImage(img, x, y, this.imageWidth, this.imageWidth);
|
||||||
|
|
||||||
this.texture.magFilter = THREE.LinearFilter;
|
this.texture.magFilter = THREE.LinearFilter;
|
||||||
this.texture.minFilter = THREE.LinearFilter;
|
this.texture.minFilter = THREE.LinearFilter;
|
||||||
this.texture.needsUpdate = true;
|
this.texture.needsUpdate = true;
|
||||||
|
|
||||||
if (this.images.length === this.imagesCount) {
|
if (this.images.length === this.imagesCount) {
|
||||||
this.emit('imageLoaded');
|
this.emit('imageLoaded');
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
import Base from './base';
|
import Base from './base';
|
||||||
import * as THREE from './three';
|
import * as THREE from './three';
|
||||||
import ColorUtil from '../attr/color-util';
|
import ColorUtil from '../attr/color-util';
|
||||||
|
import Controller from './controller/index';
|
||||||
import source from './source';
|
import source from './source';
|
||||||
import PickingMaterial from '../core/engine/picking/pickingMaterial';
|
import diff from '../util/diff';
|
||||||
import Attr from '../attr/index';
|
import { updateObjecteUniform } from '../util/object3d-util';
|
||||||
import Util from '../util';
|
import Util from '../util';
|
||||||
import Global from '../global';
|
import Global from '../global';
|
||||||
let id = 1;
|
let id = 1;
|
||||||
|
@ -20,7 +21,6 @@ function parseFields(field) {
|
||||||
}
|
}
|
||||||
return [ field ];
|
return [ field ];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Layer extends Base {
|
export default class Layer extends Base {
|
||||||
getDefaultCfg() {
|
getDefaultCfg() {
|
||||||
return {
|
return {
|
||||||
|
@ -30,8 +30,11 @@ export default class Layer extends Base {
|
||||||
minZoom: 0,
|
minZoom: 0,
|
||||||
maxZoom: 22,
|
maxZoom: 22,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
|
option: {},
|
||||||
attrOptions: {
|
attrOptions: {
|
||||||
},
|
},
|
||||||
|
scaleOptions: {},
|
||||||
|
preScaleOptions: null,
|
||||||
scales: {},
|
scales: {},
|
||||||
attrs: {},
|
attrs: {},
|
||||||
// 样式配置项
|
// 样式配置项
|
||||||
|
@ -46,7 +49,10 @@ export default class Layer extends Base {
|
||||||
// 选中时的配置项
|
// 选中时的配置项
|
||||||
selectedOptions: null,
|
selectedOptions: null,
|
||||||
// active 时的配置项
|
// active 时的配置项
|
||||||
activedOptions: null,
|
activedOptions: {
|
||||||
|
fill: [ 1.0, 0, 0, 1.0 ]
|
||||||
|
},
|
||||||
|
interactions: {},
|
||||||
animateOptions: {
|
animateOptions: {
|
||||||
enable: false
|
enable: false
|
||||||
}
|
}
|
||||||
|
@ -60,6 +66,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;
|
||||||
|
@ -76,27 +83,40 @@ export default class Layer extends Base {
|
||||||
* @param {*} type mesh类型是区别是填充还是边线
|
* @param {*} type mesh类型是区别是填充还是边线
|
||||||
*/
|
*/
|
||||||
add(object, type = 'fill') {
|
add(object, type = 'fill') {
|
||||||
type === 'fill' ? this.layerMesh = object : this.layerLineMesh = object;
|
// composer合图层绘制
|
||||||
|
if (object.type === 'composer') {
|
||||||
this._visibleWithZoom();
|
this._object3D = object;
|
||||||
this._zoomchangeHander = this._visibleWithZoom.bind(this);
|
this.scene._engine.composerLayers.push(object);
|
||||||
this.scene.on('zoomchange', this._zoomchangeHander);
|
setTimeout(() => this.scene._engine.update(), 500);
|
||||||
|
return;
|
||||||
object.onBeforeRender = () => {
|
|
||||||
const zoom = this.scene.getZoom();
|
|
||||||
object.material.setUniformsValue('u_time', this.scene._engine.clock.getElapsedTime());
|
|
||||||
object.material.setUniformsValue('u_zoom', zoom);
|
|
||||||
this._preRender();
|
|
||||||
|
|
||||||
};
|
|
||||||
// 更新
|
|
||||||
if (this._needUpdateFilter) {
|
|
||||||
this._updateFilter(object);
|
|
||||||
}
|
}
|
||||||
|
type === 'fill' ? this.layerMesh = object : this.layerLineMesh = object;
|
||||||
|
this._visibleWithZoom();
|
||||||
|
object.onBeforeRender = () => { // 每次渲染前改变状态
|
||||||
|
const zoom = this.scene.getZoom();
|
||||||
|
updateObjecteUniform(this._object3D, {
|
||||||
|
u_time: this.scene._engine.clock.getElapsedTime(),
|
||||||
|
u_zoom: zoom
|
||||||
|
});
|
||||||
|
this.preRender();
|
||||||
|
};
|
||||||
|
|
||||||
|
object.onAfterRender = () => { // 每次渲染后改变状态
|
||||||
|
this.afterRender();
|
||||||
|
};
|
||||||
this._object3D.add(object);
|
this._object3D.add(object);
|
||||||
if (type === 'fill') { this._addPickMesh(object); }
|
if (type === 'fill') {
|
||||||
|
this.get('pickingController').addPickMesh(object);
|
||||||
|
}
|
||||||
|
setTimeout(() => this.scene._engine.update(), 500);
|
||||||
}
|
}
|
||||||
remove(object) {
|
remove(object) {
|
||||||
|
if (object.type === 'composer') {
|
||||||
|
this.scene._engine.composerLayers = this.scene._engine.composerLayers.filter(layer => {
|
||||||
|
return (layer !== object);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
this._object3D.remove(object);
|
this._object3D.remove(object);
|
||||||
}
|
}
|
||||||
_getUniqueId() {
|
_getUniqueId() {
|
||||||
|
@ -107,20 +127,20 @@ 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(cfg).then(data => {
|
||||||
// command: 'geojson',
|
|
||||||
// data: cfg
|
|
||||||
// }).then(data => {
|
|
||||||
// console.log(data);
|
// console.log(data);
|
||||||
// });
|
// });
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -133,6 +153,16 @@ export default class Layer extends Base {
|
||||||
this._createAttrOption('size', field, values, Global.size);
|
this._createAttrOption('size', field, values, Global.size);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
scale(field, cfg) {
|
||||||
|
const options = this.get('scaleOptions');
|
||||||
|
const scaleDefs = options;
|
||||||
|
if (Util.isObject(field)) {
|
||||||
|
Util.mix(scaleDefs, field);
|
||||||
|
} else {
|
||||||
|
scaleDefs[field] = cfg;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
shape(field, values) {
|
shape(field, values) {
|
||||||
if (field.split(':').length === 2) {
|
if (field.split(':').length === 2) {
|
||||||
this.shapeType = field.split(':')[0];
|
this.shapeType = field.split(':')[0];
|
||||||
|
@ -152,12 +182,13 @@ export default class Layer extends Base {
|
||||||
active(enable, cfg) {
|
active(enable, cfg) {
|
||||||
if (enable === false) {
|
if (enable === false) {
|
||||||
this.set('allowActive', false);
|
this.set('allowActive', false);
|
||||||
} else if (Util.isObject(enable)) {
|
} else if (Util.isObject(enable) && enable.fill) {
|
||||||
this.set('allowActive', true);
|
this.set('allowActive', true);
|
||||||
|
if (enable.fill) enable.fill = ColorUtil.color2RGBA(enable.fill);
|
||||||
this.set('activedOptions', enable);
|
this.set('activedOptions', enable);
|
||||||
} else {
|
} else {
|
||||||
this.set('allowActive', true);
|
this.set('allowActive', true);
|
||||||
this.set('activedOptions', cfg || { fill: Global.activeColor });
|
this.set('activedOptions', cfg || { fill: ColorUtil.color2RGBA(Global.activeColor) });
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -187,11 +218,12 @@ export default class Layer extends Base {
|
||||||
this.set('styleOptions', styleOptions);
|
this.set('styleOptions', styleOptions);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
animate(field, cfg) {
|
animate(field, cfg) {
|
||||||
let animateOptions = this.get('animateOptions');
|
let animateOptions = this.get('animateOptions');
|
||||||
if (!animateOptions) {
|
if (!animateOptions) {
|
||||||
|
@ -213,6 +245,10 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
texture() {
|
texture() {
|
||||||
|
|
||||||
|
}
|
||||||
|
fitBounds() {
|
||||||
|
const extent = this.layerSource.data.extent;
|
||||||
|
this.scene.fitBounds(extent);
|
||||||
}
|
}
|
||||||
hide() {
|
hide() {
|
||||||
this._visible(false);
|
this._visible(false);
|
||||||
|
@ -222,11 +258,16 @@ 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更新
|
||||||
const scales = this.get('scales');
|
const scales = this.get('scales');
|
||||||
let scale = scales[field];
|
let scale = scales[field];
|
||||||
if (!scale) {
|
if (!scale) {
|
||||||
scale = this.layerSource.createScale(field);
|
scale = this.createScale(field);
|
||||||
scales[field] = scale;
|
scales[field] = scale;
|
||||||
}
|
}
|
||||||
return scale;
|
return scale;
|
||||||
|
@ -253,68 +294,133 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
this._setAttrOptions(attrName, attrCfg);
|
this._setAttrOptions(attrName, attrCfg);
|
||||||
}
|
}
|
||||||
|
_initControllers() {
|
||||||
|
const mappingCtr = new Controller.Mapping({ layer: this });
|
||||||
|
const pickCtr = new Controller.Picking({ layer: this });
|
||||||
|
const interactionCtr = new Controller.Interaction({ layer: this });
|
||||||
|
this.set('mappingController', mappingCtr);
|
||||||
|
this.set('pickingController', pickCtr);
|
||||||
|
this.set('interacionController', interactionCtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.init();
|
||||||
|
this.scene._engine.update();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
// 重绘 度量, 映射,顶点构建
|
||||||
|
repaint() {
|
||||||
|
this.set('scales', {});
|
||||||
|
const mappingCtr = new Controller.Mapping({ layer: this });
|
||||||
|
this.set('mappingController', mappingCtr);
|
||||||
|
// this._initAttrs();
|
||||||
|
// this._mapping();
|
||||||
|
this.redraw();
|
||||||
|
}
|
||||||
// 初始化图层
|
// 初始化图层
|
||||||
init() {
|
init() {
|
||||||
this._initAttrs();
|
this._initControllers();
|
||||||
this._scaleByZoom();
|
// this._initAttrs();
|
||||||
this._mapping();
|
this._updateDraw();
|
||||||
|
|
||||||
const activeHander = this._addActiveFeature.bind(this);
|
|
||||||
const resetHander = this._resetStyle.bind(this);
|
|
||||||
if (this.get('allowActive')) {
|
|
||||||
|
|
||||||
this.on('mousemove', activeHander);
|
|
||||||
this.on('mouseleave', resetHander);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.off('mousemove', activeHander);
|
|
||||||
this.off('mouseleave', resetHander);
|
|
||||||
}
|
}
|
||||||
|
_initInteraction() {
|
||||||
|
if (this.get('allowActive')) {
|
||||||
|
this.get('interacionController').addInteraction('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_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) {
|
||||||
|
this._activeIds = id;
|
||||||
|
if (!Array.isArray(color)) {
|
||||||
|
color = ColorUtil.color2RGBA(color);
|
||||||
|
}
|
||||||
|
updateObjecteUniform(this._object3D, {
|
||||||
|
u_activeColor: color,
|
||||||
|
u_activeId: id
|
||||||
|
});
|
||||||
|
this.scene._engine.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
_addActiveFeature(e) {
|
_addActiveFeature(e) {
|
||||||
const { featureId } = e;
|
const { featureId } = e;
|
||||||
if (featureId < 0) return;
|
this._activeIds = featureId;
|
||||||
const activeStyle = this.get('activedOptions');
|
updateObjecteUniform(this._object3D, { u_activeId: featureId });
|
||||||
// const selectFeatureIds = this.layerSource.getSelectFeatureId(featureId);
|
|
||||||
// 如果数据不显示状态则不进行高亮
|
|
||||||
if (this.layerData[featureId].hasOwnProperty('filter') && this.layerData[featureId].filter === false) { return; }
|
|
||||||
const style = Util.assign({}, this.layerData[featureId]);
|
|
||||||
style.color = ColorUtil.toRGB(activeStyle.fill).map(e => e / 255);
|
|
||||||
this.updateStyle([ featureId ], style);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_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();
|
||||||
|
}
|
||||||
|
|
||||||
_initAttrs() {
|
|
||||||
const attrOptions = this.get('attrOptions');
|
|
||||||
for (const type in attrOptions) {
|
|
||||||
if (attrOptions.hasOwnProperty(type)) {
|
|
||||||
this._updateAttr(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_updateAttr(type) {
|
|
||||||
const self = this;
|
|
||||||
const attrs = this.get('attrs');
|
|
||||||
const attrOptions = this.get('attrOptions');
|
|
||||||
const option = attrOptions[type];
|
|
||||||
option.neadUpdate = true;
|
|
||||||
const className = Util.upperFirst(type);
|
|
||||||
const fields = parseFields(option.field);
|
|
||||||
const scales = [];
|
|
||||||
for (let i = 0; i < fields.length; i++) {
|
|
||||||
const field = fields[i];
|
|
||||||
const scale = self._createScale(field);
|
|
||||||
|
|
||||||
if (type === 'color' && Util.isNil(option.values)) { // 设置 color 的默认色值
|
|
||||||
option.values = Global.colors;
|
|
||||||
}
|
|
||||||
scales.push(scale);
|
|
||||||
}
|
|
||||||
option.scales = scales;
|
|
||||||
const attr = new Attr[className](option);
|
|
||||||
attrs[type] = attr;
|
|
||||||
}
|
|
||||||
_updateSize(zoom) {
|
_updateSize(zoom) {
|
||||||
const sizeOption = this.get('attrOptions').size;
|
const sizeOption = this.get('attrOptions').size;
|
||||||
const fields = parseFields(sizeOption.field);
|
const fields = parseFields(sizeOption.field);
|
||||||
|
@ -332,95 +438,12 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
this.emit('sizeUpdated', this.zoomSizeCache[zoom]);
|
this.emit('sizeUpdated', this.zoomSizeCache[zoom]);
|
||||||
}
|
}
|
||||||
_mapping() {
|
_updateStyle(option) {
|
||||||
const self = this;
|
const newOption = { };
|
||||||
const attrs = self.get('attrs');
|
for (const key in option) {
|
||||||
const mappedData = [];
|
newOption['u_' + key] = option[key];
|
||||||
// const data = this.layerSource.propertiesData;
|
|
||||||
const data = this.layerSource.data.dataArray;
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
const record = data[i];
|
|
||||||
const newRecord = {};
|
|
||||||
newRecord.id = data[i]._id;
|
|
||||||
for (const k in attrs) {
|
|
||||||
if (attrs.hasOwnProperty(k)) {
|
|
||||||
const attr = attrs[k];
|
|
||||||
attr.needUpdate = false;
|
|
||||||
const names = attr.names;
|
|
||||||
const values = self._getAttrValues(attr, record);
|
|
||||||
if (names.length > 1) { // position 之类的生成多个字段的属性
|
|
||||||
for (let j = 0; j < values.length; j++) {
|
|
||||||
const val = values[j];
|
|
||||||
const name = names[j];
|
|
||||||
newRecord[name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
|
||||||
}
|
}
|
||||||
} else {
|
updateObjecteUniform(this._object3D, newOption);
|
||||||
newRecord[names[0]] = values.length === 1 ? values[0] : values;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newRecord.coordinates = record.coordinates;
|
|
||||||
mappedData.push(newRecord);
|
|
||||||
}
|
|
||||||
this.layerData = mappedData;
|
|
||||||
}
|
|
||||||
// 更新地图映射
|
|
||||||
_updateMaping() {
|
|
||||||
const self = this;
|
|
||||||
const attrs = self.get('attrs');
|
|
||||||
|
|
||||||
const data = this.layerSource.data.dataArray;
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
const record = data[i];
|
|
||||||
for (const attrName in attrs) {
|
|
||||||
if (attrs.hasOwnProperty(attrName) && attrs[attrName].neadUpdate) {
|
|
||||||
const attr = attrs[attrName];
|
|
||||||
const names = attr.names;
|
|
||||||
const values = self._getAttrValues(attr, record);
|
|
||||||
if (names.length > 1) { // position 之类的生成多个字段的属性
|
|
||||||
for (let j = 0; j < values.length; j++) {
|
|
||||||
const val = values[j];
|
|
||||||
const name = names[j];
|
|
||||||
this.layerData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.layerData[i][names[0]] = values.length === 1 ? values[0] : values;
|
|
||||||
|
|
||||||
}
|
|
||||||
attr.neadUpdate = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 获取属性映射的值
|
|
||||||
_getAttrValues(attr, record) {
|
|
||||||
const scales = attr.scales;
|
|
||||||
const params = [];
|
|
||||||
for (let i = 0; i < scales.length; i++) {
|
|
||||||
const scale = scales[i];
|
|
||||||
const field = scale.field;
|
|
||||||
if (scale.type === 'identity') {
|
|
||||||
params.push(scale.value);
|
|
||||||
} else {
|
|
||||||
params.push(record[field]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const indexZoom = params.indexOf('zoom');
|
|
||||||
indexZoom !== -1 ? params[indexZoom] = attr.zoom : null;
|
|
||||||
const values = attr.mapping(...params);
|
|
||||||
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) {
|
||||||
|
@ -430,106 +453,52 @@ export default class Layer extends Base {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// on(type, callback) {
|
|
||||||
|
|
||||||
// this._addPickingEvents();
|
|
||||||
// super.on(type, callback);
|
|
||||||
// }
|
|
||||||
getPickingId() {
|
|
||||||
return this.scene._engine._picking.getNextId();
|
|
||||||
}
|
|
||||||
addToPicking(object) {
|
|
||||||
this.scene._engine._picking.add(object);
|
|
||||||
}
|
|
||||||
removeFromPicking(object) {
|
|
||||||
this.scene._engine._picking.remove(object);
|
|
||||||
}
|
|
||||||
_addPickMesh(mesh) {
|
|
||||||
this._pickingMesh = new THREE.Object3D();
|
|
||||||
this._pickingMesh.name = this.layerId;
|
|
||||||
// this._visibleWithZoom();
|
|
||||||
// this.scene.on('zoomchange', () => {
|
|
||||||
// this._visibleWithZoom();
|
|
||||||
// });
|
|
||||||
|
|
||||||
this.addToPicking(this._pickingMesh);
|
|
||||||
const pickmaterial = new PickingMaterial({
|
|
||||||
u_zoom: this.scene.getZoom()
|
|
||||||
});
|
|
||||||
|
|
||||||
const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial);
|
|
||||||
pickingMesh.name = this.layerId;
|
|
||||||
pickmaterial.setDefinesvalue(this.type, true);
|
|
||||||
pickingMesh.onBeforeRender = () => {
|
|
||||||
const zoom = this.scene.getZoom();
|
|
||||||
pickingMesh.material.setUniformsValue('u_zoom', zoom);
|
|
||||||
};
|
|
||||||
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 => {
|
||||||
const { featureId, point2d, type } = e;
|
let { featureId, point2d, type } = e;
|
||||||
if (featureId < -100 && this._activeIds !== null) {
|
// TODO 瓦片图层获取选中数据信息
|
||||||
this.emit('mouseleave');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const feature = this.layerSource.getSelectFeature(featureId);
|
|
||||||
const lnglat = this.scene.containerToLngLat(point2d);
|
const lnglat = this.scene.containerToLngLat(point2d);
|
||||||
|
let feature = null;
|
||||||
|
let style = null;
|
||||||
|
if (featureId !== -999) {
|
||||||
|
const res = this.getSelectFeature(featureId, lnglat);
|
||||||
|
feature = res.feature;
|
||||||
|
style = res.style;
|
||||||
|
}
|
||||||
const target = {
|
const target = {
|
||||||
featureId,
|
featureId,
|
||||||
feature,
|
feature,
|
||||||
|
style,
|
||||||
pixel: point2d,
|
pixel: point2d,
|
||||||
|
type,
|
||||||
lnglat: { lng: lnglat.lng, lat: lnglat.lat }
|
lnglat: { lng: lnglat.lng, lat: lnglat.lat }
|
||||||
};
|
};
|
||||||
if (featureId >= 0) {
|
if (featureId >= 0) { // 拾取到元素,或者离开元素
|
||||||
this.emit(type, target);
|
this.emit(type, target);
|
||||||
}
|
}
|
||||||
|
if (featureId < 0 && this._activeIds >= 0) {
|
||||||
|
type = 'mouseleave';
|
||||||
|
this.emit(type, target);
|
||||||
|
}
|
||||||
|
this._activeIds = featureId;
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
getSelectFeature(featureId) {
|
||||||
* 更新active操作
|
const feature = this.layerSource.getSelectFeature(featureId);
|
||||||
* @param {*} featureStyleId 需要更新的要素Id
|
const style = this.layerData[featureId - 1];
|
||||||
* @param {*} style 更新的要素样式
|
return {
|
||||||
*/
|
feature,
|
||||||
updateStyle(featureStyleId, style) {
|
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] + 1);
|
|
||||||
for (let i = firstId; i < pickingId.length; i++) {
|
|
||||||
if (pickingId[i] === featureStyleId[0] + 1) {
|
|
||||||
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.get('mappingController').update();
|
||||||
const filterData = this.layerData;
|
const filterData = this.layerData;
|
||||||
this._activeIds = null; // 清空选中元素
|
this._activeIds = null; // 清空选中元素
|
||||||
const colorAttr = object.geometry.attributes.a_color;
|
const colorAttr = object.geometry.attributes.a_color;
|
||||||
|
@ -557,6 +526,7 @@ export default class Layer extends Base {
|
||||||
pickAttr.needsUpdate = true;
|
pickAttr.needsUpdate = true;
|
||||||
}
|
}
|
||||||
_visibleWithZoom() {
|
_visibleWithZoom() {
|
||||||
|
if (this._object3D === null) return;
|
||||||
const zoom = this.scene.getZoom();
|
const zoom = this.scene.getZoom();
|
||||||
const minZoom = this.get('minZoom');
|
const minZoom = this.get('minZoom');
|
||||||
const maxZoom = this.get('maxZoom');
|
const maxZoom = this.get('maxZoom');
|
||||||
|
@ -564,43 +534,56 @@ export default class Layer extends Base {
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
if (this.type === 'point') {
|
if (this.type === 'point') {
|
||||||
offset = 5;
|
offset = 5;
|
||||||
} else if (this.type === 'polyline') {
|
this.shapeType = 'text' && (offset = 10);
|
||||||
|
|
||||||
|
} else if (this.type === 'polyline' || this.type === 'line') {
|
||||||
offset = 2;
|
offset = 2;
|
||||||
|
} else if (this.type === 'polygon') {
|
||||||
|
offset = 1;
|
||||||
}
|
}
|
||||||
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.get('pickingController').removeAllMesh();
|
||||||
|
this.draw();
|
||||||
|
}
|
||||||
|
// 更新mesh
|
||||||
|
updateDraw() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
styleCfg() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置高亮要素
|
* 重置高亮要素
|
||||||
*/
|
*/
|
||||||
_resetStyle() {
|
_resetStyle() {
|
||||||
|
|
||||||
const pickingId = this.layerMesh.geometry.attributes.pickingId.array;
|
|
||||||
const colorAttr = this.layerMesh.geometry.attributes.a_color;
|
|
||||||
this._activeIds.forEach(index => {
|
|
||||||
const color = this.layerData[index].color;
|
|
||||||
const firstId = pickingId.indexOf(index + 1);
|
|
||||||
for (let i = firstId; i < pickingId.length; i++) {
|
|
||||||
if (pickingId[i] === index + 1) {
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
colorAttr.needsUpdate = true;
|
|
||||||
this._activeIds = null;
|
this._activeIds = null;
|
||||||
|
updateObjecteUniform(this._object3D, { u_activeId: 0 });
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 销毁Layer对象
|
* 销毁Layer对象
|
||||||
*/
|
*/
|
||||||
destroy() {
|
destroy() {
|
||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
|
this.clearAllInteractions();
|
||||||
|
this.clearMapEvent();
|
||||||
|
if (this._object3D.type === 'composer') {
|
||||||
|
this.remove(this._object3D);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this._object3D && this._object3D.children) {
|
if (this._object3D && this._object3D.children) {
|
||||||
let child;
|
let child;
|
||||||
for (let i = 0; i < this._object3D.children.length; i++) {
|
for (let i = 0; i < this._object3D.children.length; i++) {
|
||||||
|
@ -625,13 +608,55 @@ export default class Layer extends Base {
|
||||||
child = null;
|
child = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.layerMesh.geometry = null;
|
||||||
|
this.layerMesh.material.dispose();
|
||||||
|
this.layerMesh.material = null;
|
||||||
|
if (this._pickingMesh) {
|
||||||
|
this._pickingMesh.children[0].geometry = null;
|
||||||
|
this._pickingMesh.children[0].material.dispose();
|
||||||
|
this._pickingMesh.children[0].material = null;
|
||||||
|
}
|
||||||
|
this._buffer = null;
|
||||||
this._object3D = null;
|
this._object3D = null;
|
||||||
this.scene._engine._scene.remove(this._object3D);
|
this.scene._engine._scene.remove(this._object3D);
|
||||||
|
this.layerData.length = 0;
|
||||||
|
this.layerSource = null;
|
||||||
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;
|
||||||
}
|
}
|
||||||
_preRender() {
|
|
||||||
|
/**
|
||||||
|
* 获取图例配置项
|
||||||
|
* @param {*} field 字段
|
||||||
|
* @param {*} type 图例类型 color, size
|
||||||
|
* @return {*} 图例配置项
|
||||||
|
*/
|
||||||
|
getLegendCfg(field, type = 'color') {
|
||||||
|
// todo heatmap
|
||||||
|
if (this.type === 'heatmap' && this.shapeType === 'heatmap') {
|
||||||
|
return this.get('styleOptions').rampColors;
|
||||||
|
}
|
||||||
|
const scales = this.get('scales');
|
||||||
|
const scale = scales[field];
|
||||||
|
const colorAttrs = this.get('attrs')[type];
|
||||||
|
const lengendCfg = {};
|
||||||
|
if (scale) {
|
||||||
|
const ticks = scale.ticks;
|
||||||
|
lengendCfg.value = ticks;
|
||||||
|
lengendCfg.type = scale.type;
|
||||||
|
const values = ticks.map(value => {
|
||||||
|
const v = this._getAttrValues(colorAttrs, { [field]: value });
|
||||||
|
return type === 'color' ? ColorUtil.colorArray2RGBA(v) : v;
|
||||||
|
});
|
||||||
|
lengendCfg[type] = values;
|
||||||
|
}
|
||||||
|
return lengendCfg;
|
||||||
|
}
|
||||||
|
preRender() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
afterRender() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,12 @@ import Engine from './engine';
|
||||||
import { LAYER_MAP } from '../layer';
|
import { LAYER_MAP } from '../layer';
|
||||||
import Base from './base';
|
import Base from './base';
|
||||||
import LoadImage from './image';
|
import LoadImage from './image';
|
||||||
// import WorkerPool from './worker';
|
import FontAtlasManager from '../geom/buffer/point/text/font-manager';
|
||||||
|
import WorkerPool from '../worker/worker_pool';
|
||||||
// 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() {
|
||||||
|
@ -16,13 +18,16 @@ export default class Scene extends Base {
|
||||||
this._initMap();
|
this._initMap();
|
||||||
// this._initAttribution(); // 暂时取消,后面作为组件去加载
|
// this._initAttribution(); // 暂时取消,后面作为组件去加载
|
||||||
this.addImage();
|
this.addImage();
|
||||||
|
this.fontAtlasManager = new FontAtlasManager();
|
||||||
this._layers = [];
|
this._layers = [];
|
||||||
|
this.animateCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_initEngine(mapContainer) {
|
_initEngine(mapContainer) {
|
||||||
this._engine = new Engine(mapContainer, this);
|
this._engine = new Engine(mapContainer, this);
|
||||||
this._engine.run();
|
this.registerMapEvent();
|
||||||
// this.workerPool = new WorkerPool();
|
// this._engine.run();
|
||||||
|
this.workerPool = new WorkerPool();
|
||||||
compileBuiltinModules();
|
compileBuiltinModules();
|
||||||
}
|
}
|
||||||
// 为pickup场景添加 object 对象
|
// 为pickup场景添加 object 对象
|
||||||
|
@ -35,14 +40,20 @@ export default class Scene extends Base {
|
||||||
const MapProvider = getMap(this.mapType);
|
const MapProvider = getMap(this.mapType);
|
||||||
const Map = new MapProvider(this._attrs);
|
const Map = new MapProvider(this._attrs);
|
||||||
Map.mixMap(this);
|
Map.mixMap(this);
|
||||||
this._container = document.getElementById(Map.container);
|
this._container = Map.container;
|
||||||
// const Map = new MapProvider(this.mapContainer, this._attrs);
|
// const Map = new MapProvider(this.mapContainer, this._attrs);
|
||||||
Map.on('mapLoad', () => {
|
Map.on('mapLoad', () => {
|
||||||
this._initEngine(Map.renderDom);
|
|
||||||
this.map = Map.map;
|
this.map = Map.map;
|
||||||
|
this._initEngine(Map.renderDom);
|
||||||
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');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -63,17 +74,8 @@ export default class Scene extends Base {
|
||||||
}
|
}
|
||||||
off(type, hander) {
|
off(type, hander) {
|
||||||
if (this.map) { this.map.off(type, hander); }
|
if (this.map) { this.map.off(type, hander); }
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
@ -103,7 +105,9 @@ export default class Scene extends Base {
|
||||||
this._container.addEventListener(event, e => {
|
this._container.addEventListener(event, e => {
|
||||||
// 要素拾取
|
// 要素拾取
|
||||||
e.pixel || (e.pixel = e.point);
|
e.pixel || (e.pixel = e.point);
|
||||||
|
requestAnimationFrame(() => {
|
||||||
this._engine._picking.pickdata(e);
|
this._engine._picking.pickdata(e);
|
||||||
|
});
|
||||||
}, false);
|
}, false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -115,5 +119,31 @@ export default class Scene extends Base {
|
||||||
layer.destroy();
|
layer.destroy();
|
||||||
layer = null;
|
layer = null;
|
||||||
}
|
}
|
||||||
|
startAnimate() {
|
||||||
|
if (this.animateCount === 0) {
|
||||||
|
this.unRegsterMapEvent();
|
||||||
|
this._engine.run();
|
||||||
|
}
|
||||||
|
this.animateCount++;
|
||||||
|
}
|
||||||
|
stopAnimate() {
|
||||||
|
if (this.animateCount === 1) {
|
||||||
|
this._engine.stop();
|
||||||
|
this.registerMapEvent();
|
||||||
|
}
|
||||||
|
this.animateCount++;
|
||||||
|
}
|
||||||
|
// 地图状态变化时更新可视化渲染
|
||||||
|
registerMapEvent() {
|
||||||
|
this._updateRender = () => this._engine.update();
|
||||||
|
this.map.on('mousemove', this._updateRender);
|
||||||
|
this.map.on('mapmove', this._updateRender);
|
||||||
|
this.map.on('camerachange', this._updateRender);
|
||||||
|
}
|
||||||
|
unRegsterMapEvent() {
|
||||||
|
this.map.off('mousemove', this._updateRender);
|
||||||
|
this.map.off('mapmove', this._updateRender);
|
||||||
|
this.map.off('camerachange', this._updateRender);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
|
||||||
import Base from './base';
|
import Base from './base';
|
||||||
import Controller from './controller/index';
|
|
||||||
import { getTransform, getParser } from '../source';
|
import { getTransform, getParser } from '../source';
|
||||||
|
import { cluster, formatData } from '../source/transform/cluster';
|
||||||
|
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() {
|
||||||
|
@ -10,8 +11,8 @@ export default class Source extends Base {
|
||||||
defs: {},
|
defs: {},
|
||||||
parser: {},
|
parser: {},
|
||||||
transforms: [],
|
transforms: [],
|
||||||
scales: {
|
scaledefs: {},
|
||||||
},
|
scales: {},
|
||||||
options: {}
|
options: {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -19,19 +20,49 @@ export default class Source extends Base {
|
||||||
super(cfg);
|
super(cfg);
|
||||||
const transform = this.get('transforms');
|
const transform = this.get('transforms');
|
||||||
this._transforms = transform || [];
|
this._transforms = transform || [];
|
||||||
this._initControllers();
|
const mapType = this.get('mapType') || 'AMap';
|
||||||
|
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 = {
|
||||||
|
// dataArray: clone(this.originData.dataArray)
|
||||||
|
// }; // TODO 关闭数据备份
|
||||||
|
this.data = this.originData;
|
||||||
|
if (this.data !== null) {
|
||||||
|
this.data.extent = extent(this.data.dataArray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 数据统计
|
* 数据统计
|
||||||
|
@ -40,36 +71,42 @@ export default class Source extends Base {
|
||||||
const trans = this._transforms;
|
const trans = this._transforms;
|
||||||
trans.forEach(tran => {
|
trans.forEach(tran => {
|
||||||
const { type } = tran;
|
const { type } = tran;
|
||||||
this.data = getTransform(type)(this.data, tran);
|
const data = getTransform(type)(this.data, tran);
|
||||||
|
Object.assign(this.data, data);
|
||||||
});
|
});
|
||||||
this._transforms = trans;
|
this._transforms = trans;
|
||||||
}
|
}
|
||||||
|
transform(option) {
|
||||||
|
const data = getTransform(option.type)(this.data, option);
|
||||||
|
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() {
|
||||||
|
if (this.data === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.data.dataArray.forEach(data => {
|
this.data.dataArray.forEach(data => {
|
||||||
data.coordinates = this._coordProject(data.coordinates);
|
// data.coordinates = this._coordProject(data.coordinates);
|
||||||
|
data.coordinates = tranfrormCoord(data.coordinates, this._coorConvert.bind(this));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
createScale(field) {
|
|
||||||
const data = this.data.dataArray;
|
|
||||||
const scales = this.get('scales');
|
|
||||||
let scale = scales[field];
|
|
||||||
const scaleController = this.get('scaleController');
|
|
||||||
if (!scale) {
|
|
||||||
scale = scaleController.createScale(field, data);
|
|
||||||
scales[field] = scale;
|
|
||||||
}
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
_initControllers() {
|
|
||||||
const defs = this.get('defs');
|
|
||||||
const mapType = this.get('mapType');
|
|
||||||
this.projectFlat = getMap(mapType).project;
|
|
||||||
const scaleController = new Controller.Scale({
|
|
||||||
defs
|
|
||||||
});
|
|
||||||
this.set('scaleController', scaleController);
|
|
||||||
}
|
|
||||||
|
|
||||||
_getCoord(geo) {
|
_getCoord(geo) {
|
||||||
if (geo.geometry) {
|
if (geo.geometry) {
|
||||||
// GeoJSON feature
|
// GeoJSON feature
|
||||||
|
@ -81,7 +118,6 @@ export default class Source extends Base {
|
||||||
return geo;
|
return geo;
|
||||||
}
|
}
|
||||||
_coordProject(geo) {
|
_coordProject(geo) {
|
||||||
|
|
||||||
if (Array.isArray(geo[0][0])) {
|
if (Array.isArray(geo[0][0])) {
|
||||||
return geo.map(coor => {
|
return geo.map(coor => {
|
||||||
return this._coordProject(coor);
|
return this._coordProject(coor);
|
||||||
|
@ -89,22 +125,41 @@ export default class Source extends Base {
|
||||||
}
|
}
|
||||||
if (!Array.isArray(geo[0])) {
|
if (!Array.isArray(geo[0])) {
|
||||||
return this._coorConvert(geo);
|
return this._coorConvert(geo);
|
||||||
|
|
||||||
}
|
}
|
||||||
return geo.map(coor => {
|
return geo.map(coor => {
|
||||||
return this._coorConvert(coor);
|
return this._coorConvert(coor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_coorConvert(geo) {
|
_coorConvert(geo) {
|
||||||
|
|
||||||
const ll = this.projectFlat(geo);
|
const ll = this.projectFlat(geo);
|
||||||
return [ ll.x, ll.y, geo[2] || 0 ];
|
return [ ll.x, ll.y, geo[2] || 0 ];
|
||||||
|
|
||||||
}
|
}
|
||||||
getSelectFeature(featureId) {
|
getSelectFeature(featureId) {
|
||||||
const data = this.get('data');
|
const data = this.get('data');
|
||||||
// 如果是GeoJSON 数据返回原数
|
// 如果是GeoJSON 数据返回原数
|
||||||
return data.features ? data.features[featureId] : this.data.dataArray[featureId];
|
// 颜色编码从1开始,要素索引从0开始,所以颜色转变要素需要减1
|
||||||
|
const isCluster = this.get('isCluster') || false;
|
||||||
|
return (data.features && !isCluster)
|
||||||
|
? data.features[featureId - 1]
|
||||||
|
: this.data.dataArray[featureId - 1];
|
||||||
|
}
|
||||||
|
getSeletFeatureIndex(featureId) {
|
||||||
|
const data = this.get('data');
|
||||||
|
if (!data.features) {
|
||||||
|
return featureId - 1;
|
||||||
|
}
|
||||||
|
let featureIndex = 0;
|
||||||
|
for (let i = 0; i < this.data.dataArray.length; i++) {
|
||||||
|
const item = this.data.dataArray[i];
|
||||||
|
if (item._id === featureId) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
featureIndex++;
|
||||||
|
}
|
||||||
|
return featureIndex;
|
||||||
|
}
|
||||||
|
destroy() {
|
||||||
|
this.data = null;
|
||||||
|
this.originData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,13 @@ export { Mesh } from 'three/src/objects/Mesh.js';
|
||||||
export { Texture } from 'three/src/textures/Texture.js';
|
export { Texture } from 'three/src/textures/Texture.js';
|
||||||
export { WebGLRenderTarget } from 'three/src/renderers/WebGLRenderTarget.js';
|
export { WebGLRenderTarget } from 'three/src/renderers/WebGLRenderTarget.js';
|
||||||
export { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera.js';
|
export { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera.js';
|
||||||
|
export { OrthographicCamera } from 'three/src/cameras/OrthographicCamera.js';
|
||||||
export { BufferGeometry } from 'three/src/core/BufferGeometry.js';
|
export { BufferGeometry } from 'three/src/core/BufferGeometry.js';
|
||||||
|
export { InstancedBufferGeometry } from 'three/src/core/InstancedBufferGeometry';
|
||||||
|
export { PlaneBufferGeometry } from 'three/src/geometries/PlaneGeometry.js';
|
||||||
|
export { BoxBufferGeometry } from 'three/src/geometries/BoxGeometry.js';
|
||||||
export { Raycaster } from 'three/src/core/Raycaster.js';
|
export { Raycaster } from 'three/src/core/Raycaster.js';
|
||||||
|
export { UniformsUtils } from 'three/src/renderers/shaders/UniformsUtils.js';
|
||||||
export { Matrix4 } from 'three/src/math/Matrix4.js';
|
export { Matrix4 } from 'three/src/math/Matrix4.js';
|
||||||
export { Matrix3 } from 'three/src/math/Matrix3.js';
|
export { Matrix3 } from 'three/src/math/Matrix3.js';
|
||||||
export { Line } from 'three/src/objects/Line.js';
|
export { Line } from 'three/src/objects/Line.js';
|
||||||
|
@ -22,6 +27,7 @@ export { Vector3 } from 'three/src/math/Vector3.js';
|
||||||
export { Vector2 } from 'three/src/math/Vector2.js';
|
export { Vector2 } from 'three/src/math/Vector2.js';
|
||||||
export { ShaderMaterial } from 'three/src/materials/ShaderMaterial.js';
|
export { ShaderMaterial } from 'three/src/materials/ShaderMaterial.js';
|
||||||
export { DataTexture } from 'three/src/textures/DataTexture.js';
|
export { DataTexture } from 'three/src/textures/DataTexture.js';
|
||||||
|
export { Color } from 'three/src/math/Color.js';
|
||||||
export {
|
export {
|
||||||
Float64BufferAttribute,
|
Float64BufferAttribute,
|
||||||
Float32BufferAttribute,
|
Float32BufferAttribute,
|
||||||
|
@ -35,4 +41,5 @@ export {
|
||||||
BufferAttribute
|
BufferAttribute
|
||||||
} from 'three/src/core/BufferAttribute.js';
|
} from 'three/src/core/BufferAttribute.js';
|
||||||
|
|
||||||
|
export { InstancedBufferAttribute } from 'three/src/core/InstancedBufferAttribute'
|
||||||
// export * from '../../build/three.js';
|
// export * from '../../build/three.js';
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,101 @@
|
||||||
|
import BufferBase from '../bufferBase';
|
||||||
|
import { colorScales } from '../../../attr/colorscales';
|
||||||
|
import * as THREE from '../../../core/three';
|
||||||
|
|
||||||
|
|
||||||
|
export default class HeatmapBuffer extends BufferBase {
|
||||||
|
geometryBuffer() {
|
||||||
|
const data = this.get('data');
|
||||||
|
const positions = [];
|
||||||
|
const dirs = [];
|
||||||
|
const weights = [];
|
||||||
|
// const indices = [];
|
||||||
|
|
||||||
|
// 组织顶点数据
|
||||||
|
data.forEach(d => {
|
||||||
|
// const totalIndex = index * 4;
|
||||||
|
const coord = d.coordinates;
|
||||||
|
const weight = d.size;
|
||||||
|
const dir = this._addDir(-1, 1);
|
||||||
|
const dir1 = this._addDir(1, 1);
|
||||||
|
const dir2 = this._addDir(-1, -1);
|
||||||
|
const dir3 = this._addDir(1, -1);
|
||||||
|
positions.push(...coord, ...coord, ...coord, ...coord, ...coord, ...coord);
|
||||||
|
dirs.push(...dir, ...dir2, ...dir3, ...dir1, ...dir, ...dir3);
|
||||||
|
weights.push(weight, weight, weight, weight, weight, weight);
|
||||||
|
// indices.push(totalIndex, totalIndex + 2, totalIndex + 3, totalIndex, totalIndex + 3, totalIndex + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.attributes = {
|
||||||
|
vertices: positions,
|
||||||
|
// indices,
|
||||||
|
dirs,
|
||||||
|
weights
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_addVertex(position, dirX, dirY) {
|
||||||
|
const x = (position[0] * 2) + ((dirX + 1) / 2);
|
||||||
|
const y = (position[1] * 2) + ((dirY + 1) / 2);
|
||||||
|
const z = position[2];
|
||||||
|
return [ x, y, z ];
|
||||||
|
}
|
||||||
|
|
||||||
|
_addDir(dirX, dirY) {
|
||||||
|
const x = (dirX + 1) / 2;
|
||||||
|
const y = (dirY + 1) / 2;
|
||||||
|
return [ x, y ];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createColorRamp(colors) {
|
||||||
|
const colorImageData = getColorRamp(colors);
|
||||||
|
const colorTexture = getTexture(colorImageData);
|
||||||
|
return colorTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColorRamp(name) {
|
||||||
|
let colorscale = name;
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
canvas.width = 1;
|
||||||
|
canvas.height = 256;
|
||||||
|
const gradient = ctx.createLinearGradient(0, 0, 0, 256);
|
||||||
|
let data = null;
|
||||||
|
if (typeof (colorscale) === 'string') {
|
||||||
|
colorscale = colorScales[name];
|
||||||
|
}
|
||||||
|
if (Object.prototype.toString.call(colorscale) === '[object Object]') {
|
||||||
|
const min = colorscale.positions[0];
|
||||||
|
const max = colorscale.positions[colorscale.positions.length - 1];
|
||||||
|
|
||||||
|
for (let i = 0; i < colorscale.colors.length; ++i) {
|
||||||
|
const value = (colorscale.positions[i] - min) / (max - min);
|
||||||
|
gradient.addColorStop(value, colorscale.colors[i]);
|
||||||
|
}
|
||||||
|
ctx.fillStyle = gradient;
|
||||||
|
ctx.fillRect(0, 0, 1, 256);
|
||||||
|
data = new Uint8ClampedArray(ctx.getImageData(0, 0, 1, 256).data);
|
||||||
|
}
|
||||||
|
if (Object.prototype.toString.call(colorscale) === '[object Uint8Array]') {
|
||||||
|
data = ctx.createImageData(1, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ImageData(data, 1, 256);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTexture(image) {
|
||||||
|
const texture = new THREE.Texture(image);
|
||||||
|
texture.wrapS = THREE.ClampToEdgeWrapping;
|
||||||
|
texture.wrapT = THREE.ClampToEdgeWrapping;
|
||||||
|
texture.magFilter = THREE.NearestFilter;
|
||||||
|
texture.minFilter = THREE.NearestFilter;
|
||||||
|
texture.format = THREE.RGBAFormat;
|
||||||
|
texture.type = THREE.UnsignedByteType;
|
||||||
|
texture.needsUpdate = true;
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default class ImageBuffer extends BufferBase {
|
||||||
const uv = [ 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 ];
|
const uv = [ 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 ];
|
||||||
const texture = new THREE.Texture(image);
|
const texture = new THREE.Texture(image);
|
||||||
texture.magFilter = THREE.LinearFilter;
|
texture.magFilter = THREE.LinearFilter;
|
||||||
texture.minFilter = THREE.LinearFilter;
|
texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||||
texture.needsUpdate = true;
|
texture.needsUpdate = true;
|
||||||
const attributes = {
|
const attributes = {
|
||||||
vertices: new Float32Array(positions),
|
vertices: new Float32Array(positions),
|
||||||
|
|
|
@ -75,7 +75,7 @@ export default class LineBuffer extends BufferBase {
|
||||||
}
|
}
|
||||||
_getMeshLineAttributes() {
|
_getMeshLineAttributes() {
|
||||||
const layerData = this.get('layerData');
|
const layerData = this.get('layerData');
|
||||||
const { lineType } = this.get('style');
|
const { dashArray } = this.get('style');
|
||||||
const positions = [];
|
const positions = [];
|
||||||
const pickingIds = [];
|
const pickingIds = [];
|
||||||
const normal = [];
|
const normal = [];
|
||||||
|
@ -84,10 +84,11 @@ export default class LineBuffer extends BufferBase {
|
||||||
const indexArray = [];
|
const indexArray = [];
|
||||||
const sizes = [];
|
const sizes = [];
|
||||||
const attrDistance = [];
|
const attrDistance = [];
|
||||||
|
const attrDashArray = [];
|
||||||
layerData.forEach(item => {
|
layerData.forEach(item => {
|
||||||
const props = item;
|
const props = item;
|
||||||
const positionCount = positions.length / 3;
|
const positionCount = positions.length / 3;
|
||||||
const attr = lineShape.Line(item.coordinates, props, positionCount, (lineType !== 'soild'));
|
const attr = lineShape.Line(item.coordinates, props, positionCount, dashArray);
|
||||||
positions.push(...attr.positions);
|
positions.push(...attr.positions);
|
||||||
normal.push(...attr.normal);
|
normal.push(...attr.normal);
|
||||||
miter.push(...attr.miter);
|
miter.push(...attr.miter);
|
||||||
|
@ -96,6 +97,7 @@ export default class LineBuffer extends BufferBase {
|
||||||
sizes.push(...attr.sizes);
|
sizes.push(...attr.sizes);
|
||||||
attrDistance.push(...attr.attrDistance);
|
attrDistance.push(...attr.attrDistance);
|
||||||
pickingIds.push(...attr.pickingIds);
|
pickingIds.push(...attr.pickingIds);
|
||||||
|
attrDashArray.push(...attr.dashArray);
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
positions,
|
positions,
|
||||||
|
@ -105,22 +107,26 @@ export default class LineBuffer extends BufferBase {
|
||||||
indexArray,
|
indexArray,
|
||||||
pickingIds,
|
pickingIds,
|
||||||
sizes,
|
sizes,
|
||||||
attrDistance
|
attrDistance,
|
||||||
|
attrDashArray
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_toAttributes(bufferStruct) {
|
_toAttributes(bufferStruct) {
|
||||||
const vertCount = bufferStruct.verts.length;
|
const vertCount = bufferStruct.verts.length;
|
||||||
const vertices = new Float32Array(vertCount * 3);
|
const vertices = new Float32Array(vertCount * 3);
|
||||||
|
const pickingIds = new Float32Array(vertCount);
|
||||||
const inposs = new Float32Array(vertCount * 4);
|
const inposs = new Float32Array(vertCount * 4);
|
||||||
const colors = new Float32Array(vertCount * 4);
|
const colors = new Float32Array(vertCount * 4);
|
||||||
for (let i = 0; i < vertCount; i++) {
|
for (let i = 0; i < vertCount; i++) {
|
||||||
const index = bufferStruct.indexs[i];
|
const index = bufferStruct.indexs[i];
|
||||||
const color = bufferStruct.style[index].color;
|
const color = bufferStruct.style[index].color;
|
||||||
|
const id = bufferStruct.style[index].id;
|
||||||
vertices[i * 3] = bufferStruct.verts[i][0];
|
vertices[i * 3] = bufferStruct.verts[i][0];
|
||||||
vertices[i * 3 + 1] = bufferStruct.verts[i][1];
|
vertices[i * 3 + 1] = bufferStruct.verts[i][1];
|
||||||
vertices[i * 3 + 2] = bufferStruct.verts[i][2];
|
vertices[i * 3 + 2] = bufferStruct.verts[i][2];
|
||||||
colors[i * 4] = color[0];
|
colors[i * 4] = color[0];
|
||||||
|
pickingIds[i] = id;
|
||||||
colors[i * 4 + 1] = color[1];
|
colors[i * 4 + 1] = color[1];
|
||||||
colors[i * 4 + 2] = color[2];
|
colors[i * 4 + 2] = color[2];
|
||||||
colors[i * 4 + 3] = color[3];
|
colors[i * 4 + 3] = color[3];
|
||||||
|
@ -133,6 +139,7 @@ export default class LineBuffer extends BufferBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
pickingIds,
|
||||||
vertices,
|
vertices,
|
||||||
colors,
|
colors,
|
||||||
inposs
|
inposs
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { packUint8ToFloat } from '../../../util/vertex-compress';
|
||||||
|
import Global from '../../../global';
|
||||||
|
const { pointShape } = Global;
|
||||||
|
|
||||||
|
const LEFT_SHIFT17 = 131072.0;
|
||||||
|
// const LEFT_SHIFT18 = 262144.0;
|
||||||
|
// const LEFT_SHIFT19 = 524288.0;
|
||||||
|
// const LEFT_SHIFT20 = 1048576.0;
|
||||||
|
const LEFT_SHIFT21 = 2097152.0;
|
||||||
|
// const LEFT_SHIFT22 = 4194304.0;
|
||||||
|
const LEFT_SHIFT23 = 8388608.0;
|
||||||
|
// const LEFT_SHIFT24 = 16777216.0;
|
||||||
|
|
||||||
|
export default function circleBuffer(layerData) {
|
||||||
|
const index = [];
|
||||||
|
const aPosition = [];
|
||||||
|
const aPackedData = [];
|
||||||
|
|
||||||
|
layerData.forEach(({ size = 0, color, id, coordinates, shape }, i) => {
|
||||||
|
|
||||||
|
const shapeIndex = pointShape['2d'].indexOf(shape) || 0;
|
||||||
|
|
||||||
|
if (isNaN(size)) {
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pack color(vec4) into vec2
|
||||||
|
const packedColor = [
|
||||||
|
packUint8ToFloat(color[0] * 255, color[1] * 255),
|
||||||
|
packUint8ToFloat(color[2] * 255, color[3] * 255)
|
||||||
|
];
|
||||||
|
|
||||||
|
// construct point coords
|
||||||
|
[
|
||||||
|
[ -1, -1 ],
|
||||||
|
[ 1, -1 ],
|
||||||
|
[ 1, 1 ],
|
||||||
|
[ -1, 1 ]
|
||||||
|
].forEach(extrude => {
|
||||||
|
// vec4(color, color, (4-bit extrude, 4-bit shape, 16-bit size), id)
|
||||||
|
aPackedData.push(
|
||||||
|
...packedColor,
|
||||||
|
(extrude[0] + 1) * LEFT_SHIFT23 + (extrude[1] + 1) * LEFT_SHIFT21
|
||||||
|
+ shapeIndex * LEFT_SHIFT17
|
||||||
|
+ size,
|
||||||
|
id
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO:如果使用相对瓦片坐标,还可以进一步压缩
|
||||||
|
aPosition.push(...coordinates, ...coordinates, ...coordinates, ...coordinates);
|
||||||
|
index.push(...[ 0, 1, 2, 0, 2, 3 ].map(n => n + i * 4));
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
aPosition,
|
||||||
|
index,
|
||||||
|
aPackedData
|
||||||
|
};
|
||||||
|
}
|
|
@ -29,6 +29,12 @@ export default function fillBuffer(layerData) {
|
||||||
throw new Error('Invalid shape type: ' + shape);
|
throw new Error('Invalid shape type: ' + shape);
|
||||||
}
|
}
|
||||||
toPointShapeAttributes(polygon, coordinates, { size, shape, color, id }, attribute);
|
toPointShapeAttributes(polygon, coordinates, { size, shape, color, id }, attribute);
|
||||||
|
// toPointShapeAttributes(polygon, null, {}, attribute);
|
||||||
|
// instanced attributes
|
||||||
|
// attribute.vertices.push(...coordinates);
|
||||||
|
// attribute.a_size.push(...size);
|
||||||
|
// attribute.colors.push(...color);
|
||||||
|
// attribute.pickingIds.push(id);
|
||||||
|
|
||||||
});
|
});
|
||||||
return attribute;
|
return attribute;
|
||||||
|
@ -78,5 +84,8 @@ function toPointShapeAttributes(polygon, geo, style, attribute) {
|
||||||
attribute.colors.push(...color, ...color, ...color);
|
attribute.colors.push(...color, ...color, ...color);
|
||||||
attribute.pickingIds.push(id, id, id);
|
attribute.pickingIds.push(id, id, id);
|
||||||
|
|
||||||
|
// attribute.shapePositions.push(ax, ay, az, bx, by, bz, cx, cy, cz);
|
||||||
|
// attribute.normals.push(nx, ny, nz, nx, ny, nz, nx, ny, nz);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,3 +2,4 @@ export { default as FillBuffer } from './fillBuffer';
|
||||||
export { default as StrokeBuffer } from './strokeBuffer';
|
export { default as StrokeBuffer } from './strokeBuffer';
|
||||||
export { default as ImageBuffer } from './imageBuffer';
|
export { default as ImageBuffer } from './imageBuffer';
|
||||||
export { default as NormalBuffer } from './normalBuffer';
|
export { default as NormalBuffer } from './normalBuffer';
|
||||||
|
export { default as CircleBuffer } from './circleBuffer';
|
||||||
|
|
|
@ -13,7 +13,5 @@ export default function NormalBuffer(layerData) {
|
||||||
attributes.sizes.push(size);
|
attributes.sizes.push(size);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,246 +0,0 @@
|
||||||
// const SDFCommonWordsKey = '_AMap_sdf_com_words';
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * SDF 常用字获取/存储/check
|
|
||||||
// *
|
|
||||||
// */
|
|
||||||
// const SDFCommonWords = {
|
|
||||||
|
|
||||||
// store() {
|
|
||||||
|
|
||||||
// },
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 检查一个字符是否在常用字中
|
|
||||||
// * @param {*} charcode 汉字
|
|
||||||
// */
|
|
||||||
// check(charcode) {
|
|
||||||
// const range = this.range || [];
|
|
||||||
// const info = this.info || {};
|
|
||||||
|
|
||||||
// if (typeof charcode !== 'number') {
|
|
||||||
|
|
||||||
// charcode = charcode.substr(0).charCodeAt(0);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for (let i = 0; i < range.length; i++) {
|
|
||||||
// const curRange = range[i];
|
|
||||||
// const [ rangeStart, rangeEnd ] = curRange.split('-');
|
|
||||||
|
|
||||||
// if (charcode >= rangeStart && charcode <= rangeEnd) {
|
|
||||||
|
|
||||||
// const curInfo = info[curRange] && info[curRange].info || {};
|
|
||||||
|
|
||||||
// if (curInfo[charcode]) {
|
|
||||||
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return false;
|
|
||||||
// },
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 获取纹理和位置信息
|
|
||||||
// * @param list
|
|
||||||
// * @param cb
|
|
||||||
// */
|
|
||||||
// getImagesAndInfo(list, cb) {
|
|
||||||
// const range = this.range;
|
|
||||||
|
|
||||||
|
|
||||||
// },
|
|
||||||
|
|
||||||
// loadCanvas(url, range, done) {
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// const xhr = new XMLHttpRequest();
|
|
||||||
// xhr.open('GET', url);
|
|
||||||
|
|
||||||
// // 直接用 blob 格式 load 图片文件,方便直接转换成 base64
|
|
||||||
// // 转成 base64 便于存储
|
|
||||||
// // 使用 canvas 转换 base64 容易有损
|
|
||||||
// xhr.responseType = 'blob';
|
|
||||||
// xhr.onerror = function() {
|
|
||||||
// done({ code: 0 });
|
|
||||||
// };
|
|
||||||
|
|
||||||
// xhr.onload = function() {
|
|
||||||
|
|
||||||
// if (xhr.status === 200) {
|
|
||||||
// const reader = new FileReader();
|
|
||||||
|
|
||||||
// reader.onload = () => {
|
|
||||||
|
|
||||||
// done(reader.result, range);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// reader.readAsDataURL(xhr.response);
|
|
||||||
// } else {
|
|
||||||
// done({ code: 0 });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// xhr.send();
|
|
||||||
// } catch (err) {
|
|
||||||
|
|
||||||
// done({ code: 0 });
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
|
|
||||||
// loadImages(urls = []) {
|
|
||||||
// const deferred = $.Deferred();
|
|
||||||
// const totalNumbers = urls.length;
|
|
||||||
// const localInfo = this.info;
|
|
||||||
// let loadPicNum = 0;
|
|
||||||
|
|
||||||
// for (let i = 0; i < urls.length; i++) {
|
|
||||||
// const { url, range } = urls[i];
|
|
||||||
|
|
||||||
// this.loadCanvas(url, range, (base64, range) => {
|
|
||||||
|
|
||||||
// // image to base64
|
|
||||||
// loadPicNum++;
|
|
||||||
|
|
||||||
// !localInfo[range] && (localInfo[range] = {});
|
|
||||||
|
|
||||||
// localInfo[range].pic = base64;
|
|
||||||
|
|
||||||
// this.info = localInfo;
|
|
||||||
|
|
||||||
// // todo: temp 暂时用 localstorage 存储,因为数据比较大,最好使用 indexDB
|
|
||||||
// localStorage.setItem(SDFCommonWordsKey, JSON.stringify(localInfo));
|
|
||||||
|
|
||||||
// if (loadPicNum === totalNumbers) {
|
|
||||||
|
|
||||||
// deferred.resolve();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return deferred;
|
|
||||||
// },
|
|
||||||
|
|
||||||
// loadInfo(urls) {
|
|
||||||
// const deferred = $.Deferred();
|
|
||||||
// const totalNumbers = urls.length;
|
|
||||||
// const localInfo = this.info;
|
|
||||||
// let loadInfoNum = 0;
|
|
||||||
|
|
||||||
// for (let i = 0; i < urls.length; i++) {
|
|
||||||
// const { url, range } = urls[i];
|
|
||||||
|
|
||||||
// $.ajax({
|
|
||||||
// url,
|
|
||||||
// dataType: 'json',
|
|
||||||
// success: data => {
|
|
||||||
// loadInfoNum++;
|
|
||||||
|
|
||||||
// !localInfo[range] && (localInfo[range] = {});
|
|
||||||
|
|
||||||
// localInfo[range].info = data;
|
|
||||||
|
|
||||||
// this.info = localInfo;
|
|
||||||
|
|
||||||
// localStorage.setItem(SDFCommonWordsKey, JSON.stringify(localInfo));
|
|
||||||
|
|
||||||
// if (loadInfoNum === totalNumbers) {
|
|
||||||
|
|
||||||
// deferred.resolve();
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// error: () => {
|
|
||||||
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return deferred;
|
|
||||||
|
|
||||||
// },
|
|
||||||
|
|
||||||
// getTotalAssets(info, cb) {
|
|
||||||
// const { range = [], urlPrefix } = info;
|
|
||||||
// const picUrls = [];
|
|
||||||
// const infoUrls = [];
|
|
||||||
|
|
||||||
// this.range = range;
|
|
||||||
|
|
||||||
// for (let i = 0; i < range.length; i++) {
|
|
||||||
// const curRange = range[i];
|
|
||||||
// const baseUrl = urlPrefix + curRange;
|
|
||||||
// const picUrl = baseUrl + '.png';
|
|
||||||
// const infoUrl = baseUrl + '.json';
|
|
||||||
|
|
||||||
// picUrls.push({ range: curRange, url: picUrl });
|
|
||||||
// infoUrls.push({ range: curRange, url: infoUrl });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const imageDeferred = this.loadImages(picUrls);
|
|
||||||
// const infoDeferred = this.loadInfo(infoUrls);
|
|
||||||
|
|
||||||
// $.when(imageDeferred, infoDeferred)
|
|
||||||
// .then(() => {
|
|
||||||
|
|
||||||
// // all info load complete
|
|
||||||
// // console.log("all info load complete", " -- ", 1);
|
|
||||||
// cb && cb(this.info);
|
|
||||||
// }, () => {
|
|
||||||
|
|
||||||
// // fail
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// // 获取数据
|
|
||||||
// getData(cb) {
|
|
||||||
|
|
||||||
// if (!_.isEmpty(this.info)) {
|
|
||||||
|
|
||||||
// cb && cb(this.info);
|
|
||||||
// } else {
|
|
||||||
|
|
||||||
// this.getRemoteData(cb);
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 从服务获取数据,什么时候强制去取一回数据?过期?
|
|
||||||
// * @param cb
|
|
||||||
// */
|
|
||||||
// getRemoteData(cb) {
|
|
||||||
// const self = this;
|
|
||||||
|
|
||||||
// $.ajax({
|
|
||||||
// url: '/getcommonwords',
|
|
||||||
// dataType: 'json',
|
|
||||||
// success: data => {
|
|
||||||
|
|
||||||
// if (data.code == 1) {
|
|
||||||
|
|
||||||
// const info = data.data;
|
|
||||||
|
|
||||||
// self.getTotalAssets(info, cb);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
|
|
||||||
// destroy() {
|
|
||||||
|
|
||||||
// },
|
|
||||||
|
|
||||||
// init() {
|
|
||||||
// let info = localStorage.getItem(SDFCommonWordsKey);
|
|
||||||
// this.range = [];
|
|
||||||
// this.info = {};
|
|
||||||
|
|
||||||
// if (info) {
|
|
||||||
// info = JSON.parse(info);
|
|
||||||
// this.range = Object.keys(info);
|
|
||||||
// this.info = info;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.info = info || {};
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// export default SDFCommonWords;
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
export default function TextBuffer(layerData, fontAtlasManager) {
|
||||||
|
const characterSet = [];
|
||||||
|
layerData.forEach(element => {
|
||||||
|
let text = element.shape || '';
|
||||||
|
text = text.toString();
|
||||||
|
for (let j = 0; j < text.length; j++) {
|
||||||
|
if (characterSet.indexOf(text[j]) === -1) {
|
||||||
|
characterSet.push(text[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fontAtlasManager.setProps({
|
||||||
|
characterSet
|
||||||
|
});
|
||||||
|
const attr = drawGlyph(layerData, fontAtlasManager);
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
function drawGlyph(layerData, fontAtlasManager) {
|
||||||
|
const attributes = {
|
||||||
|
originPoints: [],
|
||||||
|
textSizes: [],
|
||||||
|
textOffsets: [],
|
||||||
|
colors: [],
|
||||||
|
textureElements: [],
|
||||||
|
pickingIds: []
|
||||||
|
};
|
||||||
|
const { texture, fontAtlas, mapping, scale } = fontAtlasManager;
|
||||||
|
layerData.forEach(function(element) {
|
||||||
|
const size = element.size;
|
||||||
|
const pos = element.coordinates;
|
||||||
|
let text = element.shape || '';
|
||||||
|
text = text.toString();
|
||||||
|
const pen = {
|
||||||
|
x: (-text.length * size) / 2,
|
||||||
|
y: 0
|
||||||
|
};
|
||||||
|
for (let i = 0; i < text.length; i++) {
|
||||||
|
const metric = mapping[text[i]];
|
||||||
|
const { x, y, width, height } = metric;
|
||||||
|
const color = element.color;
|
||||||
|
const offsetX = pen.x;
|
||||||
|
const offsetY = pen.y;
|
||||||
|
attributes.pickingIds.push(
|
||||||
|
element.id,
|
||||||
|
element.id,
|
||||||
|
element.id,
|
||||||
|
element.id,
|
||||||
|
element.id,
|
||||||
|
element.id
|
||||||
|
);
|
||||||
|
attributes.textOffsets.push(
|
||||||
|
// 文字在词语的偏移量
|
||||||
|
offsetX,
|
||||||
|
offsetY,
|
||||||
|
offsetX,
|
||||||
|
offsetY,
|
||||||
|
offsetX,
|
||||||
|
offsetY,
|
||||||
|
offsetX,
|
||||||
|
offsetY,
|
||||||
|
offsetX,
|
||||||
|
offsetY,
|
||||||
|
offsetX,
|
||||||
|
offsetY
|
||||||
|
);
|
||||||
|
attributes.originPoints.push(
|
||||||
|
// 词语的经纬度坐标
|
||||||
|
pos[0],
|
||||||
|
pos[1],
|
||||||
|
0,
|
||||||
|
pos[0],
|
||||||
|
pos[1],
|
||||||
|
0,
|
||||||
|
pos[0],
|
||||||
|
pos[1],
|
||||||
|
0,
|
||||||
|
pos[0],
|
||||||
|
pos[1],
|
||||||
|
0,
|
||||||
|
pos[0],
|
||||||
|
pos[1],
|
||||||
|
0,
|
||||||
|
pos[0],
|
||||||
|
pos[1],
|
||||||
|
0
|
||||||
|
);
|
||||||
|
attributes.textSizes.push(
|
||||||
|
size,
|
||||||
|
size * scale,
|
||||||
|
0,
|
||||||
|
size * scale,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
size,
|
||||||
|
size * scale,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
size,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
attributes.colors.push(
|
||||||
|
...color,
|
||||||
|
...color,
|
||||||
|
...color,
|
||||||
|
...color,
|
||||||
|
...color,
|
||||||
|
...color
|
||||||
|
);
|
||||||
|
attributes.textureElements.push(
|
||||||
|
// 文字纹理坐标
|
||||||
|
x + width,
|
||||||
|
y,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
x,
|
||||||
|
y + height,
|
||||||
|
x + width,
|
||||||
|
y,
|
||||||
|
x,
|
||||||
|
y + height,
|
||||||
|
x + width,
|
||||||
|
y + height
|
||||||
|
);
|
||||||
|
pen.x = pen.x + size;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
attributes.texture = texture;
|
||||||
|
attributes.fontAtlas = fontAtlas;
|
||||||
|
return attributes;
|
||||||
|
}
|
|
@ -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 './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,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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,181 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
import { getJSON } from '../../../util/ajax';
|
|
||||||
import EventEmitter from 'wolfy87-eventemitter';
|
|
||||||
import Global from '../../../global';
|
|
||||||
// const Space = 1;
|
|
||||||
const metrics = {
|
|
||||||
buffer: 3,
|
|
||||||
family: 'ios9',
|
|
||||||
size: 24
|
|
||||||
};
|
|
||||||
export default function TextBuffer(layerData, style) {
|
|
||||||
EventEmitter.call(this);
|
|
||||||
const attributes = {
|
|
||||||
originPoints: [],
|
|
||||||
textSizes: [],
|
|
||||||
textOffsets: [],
|
|
||||||
colors: [],
|
|
||||||
textureElements: []
|
|
||||||
};
|
|
||||||
const { textOffset = [ 0, 0 ] } = style;
|
|
||||||
const chars = [];
|
|
||||||
const textChars = {};
|
|
||||||
layerData.forEach(element => {
|
|
||||||
let text = element.shape || '';
|
|
||||||
text = text.toString();
|
|
||||||
for (let j = 0; j < text.length; j++) {
|
|
||||||
const code = text.charCodeAt(j);
|
|
||||||
textChars[text] = 0;
|
|
||||||
if (chars.indexOf(code) === -1) {
|
|
||||||
chars.push(text.charCodeAt(j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
loadTextInfo(chars, (chars, texture) => {
|
|
||||||
layerData.forEach(element => {
|
|
||||||
const size = element.size;
|
|
||||||
const pos = layerData.coordinates;
|
|
||||||
const pen = { x: textOffset[0], y: textOffset[1] };
|
|
||||||
let text = element.shape || '';
|
|
||||||
text = text.toString();
|
|
||||||
for (let i = 0; i < text.length; i++) {
|
|
||||||
const color = element.color;
|
|
||||||
drawGlyph(chars, pos, text[i], pen, size, attributes.colors, attributes.textureElements, attributes.originPoints, attributes.textSizes, attributes.textOffsets, color);
|
|
||||||
}
|
|
||||||
this.emit('completed', { attributes, texture });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadTextInfo(chars, done) {
|
|
||||||
getJSON({
|
|
||||||
url: `${Global.sdfHomeUrl}/getsdfdata?chars=${chars.join('|')}`
|
|
||||||
}, (e, info) => {
|
|
||||||
loadTextTexture(info.url, texture => {
|
|
||||||
done(info.info, texture);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function loadTextTexture(url, cb) {
|
|
||||||
|
|
||||||
|
|
||||||
const img = new Image();
|
|
||||||
img.crossOrigin = 'anonymous';
|
|
||||||
|
|
||||||
img.onload = () => {
|
|
||||||
const textTexture = this._creatTexture(img);
|
|
||||||
cb(textTexture);
|
|
||||||
};
|
|
||||||
img.src = url;
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 计算每个标注词语的位置
|
|
||||||
* @param {*} chars 文本信息
|
|
||||||
* @param {*} pos 文字三维空间坐标
|
|
||||||
* @param {*} text 字符
|
|
||||||
* @param {*} pen 字符在词语的偏移量
|
|
||||||
* @param {*} size 字体大小
|
|
||||||
* @param {*} colors 颜色
|
|
||||||
* @param {*} textureElements 纹理坐标
|
|
||||||
* @param {*} originPoints 初始位置数据
|
|
||||||
* @param {*} textSizes 文字大小数组
|
|
||||||
* @param {*} textOffsets 字体偏移量数据
|
|
||||||
* @param {*} color 文字颜色
|
|
||||||
*/
|
|
||||||
function drawGlyph(chars, pos, text, pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color) {
|
|
||||||
const chr = text.charCodeAt(0);
|
|
||||||
const metric = chars[chr];
|
|
||||||
if (!metric) return;
|
|
||||||
const scale = size / metrics.size;
|
|
||||||
|
|
||||||
let width = metric[0];
|
|
||||||
let height = metric[1];
|
|
||||||
const posX = metric[5];
|
|
||||||
const posY = metric[6];
|
|
||||||
const buffer = metrics.buffer;
|
|
||||||
if (width > 0 && height > 0) {
|
|
||||||
width += buffer * 2;
|
|
||||||
height += buffer * 2;
|
|
||||||
const originX = 0;
|
|
||||||
const originY = 0;
|
|
||||||
const offsetX = pen.x;
|
|
||||||
const offsetY = pen.y;
|
|
||||||
originPoints.push(
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
);
|
|
||||||
const bx = 0;
|
|
||||||
const by = metrics.size / 2 + buffer;
|
|
||||||
textSizes.push(
|
|
||||||
((bx - buffer + width) * scale), (height - by) * scale,
|
|
||||||
((bx - buffer) * scale), (height - by) * scale,
|
|
||||||
((bx - buffer) * scale), -by * scale,
|
|
||||||
|
|
||||||
((bx - buffer + width) * scale), (height - by) * scale,
|
|
||||||
((bx - buffer) * scale), -by * scale,
|
|
||||||
((bx - buffer + width) * scale), -by * scale,
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
textOffsets.push(
|
|
||||||
offsetX, offsetY,
|
|
||||||
offsetX, offsetY,
|
|
||||||
offsetX, offsetY,
|
|
||||||
offsetX, offsetY,
|
|
||||||
offsetX, offsetY,
|
|
||||||
offsetX, offsetY,
|
|
||||||
);
|
|
||||||
|
|
||||||
colors.push(
|
|
||||||
...color,
|
|
||||||
...color,
|
|
||||||
...color,
|
|
||||||
...color,
|
|
||||||
...color,
|
|
||||||
...color,
|
|
||||||
);
|
|
||||||
textureElements.push(
|
|
||||||
|
|
||||||
posX + width, posY,
|
|
||||||
posX, posY,
|
|
||||||
posX, posY + height,
|
|
||||||
|
|
||||||
posX + width, posY,
|
|
||||||
posX, posY + height,
|
|
||||||
posX + width, posY + height
|
|
||||||
);
|
|
||||||
}
|
|
||||||
pen.x = pen.x + size * 1.8;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// function measureText(text, size) {
|
|
||||||
// const dimensions = {
|
|
||||||
// advance: 0
|
|
||||||
// };
|
|
||||||
// const metrics = this.metrics;
|
|
||||||
// const scale = size / metrics.size;
|
|
||||||
// for (let i = 0; i < text.length; i++) {
|
|
||||||
// const code = text.charCodeAt(i);
|
|
||||||
// const horiAdvance = metrics.chars[code][4];
|
|
||||||
|
|
||||||
// dimensions.advance += (horiAdvance + Space) * scale;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return dimensions;
|
|
||||||
// }
|
|
||||||
// function creatTexture(image) {
|
|
||||||
// this.bufferStruct.textSize = [ image.width, image.height ];
|
|
||||||
// const texture = new THREE.Texture(image);
|
|
||||||
// texture.minFilter = THREE.LinearFilter;
|
|
||||||
// texture.magFilter = THREE.ClampToEdgeWrapping;
|
|
||||||
// texture.needsUpdate = true;
|
|
||||||
// return texture;
|
|
||||||
// }
|
|
|
@ -15,17 +15,16 @@ export class RasterBuffer extends BufferBase {
|
||||||
];
|
];
|
||||||
const imgPosUv = [ 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 ];
|
const imgPosUv = [ 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 ];
|
||||||
const size = this.get('size');
|
const size = this.get('size');
|
||||||
|
|
||||||
const texture = new THREE.DataTexture(new Float32Array(data), width, height, THREE.LuminanceFormat, THREE.FloatType);
|
const texture = new THREE.DataTexture(new Float32Array(data), width, height, THREE.LuminanceFormat, THREE.FloatType);
|
||||||
texture.generateMipmaps = true;
|
|
||||||
texture.needsUpdate = true;
|
texture.needsUpdate = true;
|
||||||
const colors = this.get('rampColors');
|
const colors = this.get('rampColors');
|
||||||
const colorImageData = this.getColorRamp(colors);
|
const colorImageData = this.getColorRamp(colors);
|
||||||
const colorTexture = this._getTexture(colorImageData);
|
const colorTexture = this._getTexture(colorImageData); // 颜色纹理
|
||||||
this.bufferStruct.position = positions;
|
this.bufferStruct.position = positions;
|
||||||
this.bufferStruct.uv = imgPosUv;
|
this.bufferStruct.uv = imgPosUv;
|
||||||
this.bufferStruct.u_raster = texture;//
|
this.bufferStruct.u_raster = texture;//
|
||||||
this.bufferStruct.u_extent = [ coordinates[0][0], coordinates[0][1], coordinates[1][0], coordinates[1][1] ];
|
this.bufferStruct.u_extent = [ coordinates[0][0], coordinates[0][1], coordinates[1][0], coordinates[1][1] ];
|
||||||
|
|
||||||
this.bufferStruct.u_colorTexture = colorTexture; // 颜色表‘=
|
this.bufferStruct.u_colorTexture = colorTexture; // 颜色表‘=
|
||||||
const triangles = this._buildTriangles(width, height, size, this.bufferStruct.u_extent);
|
const triangles = this._buildTriangles(width, height, size, this.bufferStruct.u_extent);
|
||||||
const attributes = {
|
const attributes = {
|
||||||
|
@ -68,16 +67,23 @@ export class RasterBuffer extends BufferBase {
|
||||||
return new ImageData(data, 16, 16);
|
return new ImageData(data, 16, 16);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 颜色纹理
|
||||||
|
* @param {*} image 颜色图片
|
||||||
|
* @return {texture} texture
|
||||||
|
*/
|
||||||
_getTexture(image) {
|
_getTexture(image) {
|
||||||
const texture1 = new THREE.Texture(image);
|
const texture1 = new THREE.Texture(image);
|
||||||
texture1.magFilter = THREE.LinearFilter;
|
texture1.magFilter = THREE.LinearFilter;
|
||||||
texture1.minFilter = THREE.LinearFilter;
|
texture1.minFilter = THREE.LinearFilter;
|
||||||
texture1.format = THREE.RGBAFormat;
|
texture1.format = THREE.RGBAFormat;
|
||||||
texture1.type = THREE.UnsignedByteType;
|
texture1.type = THREE.UnsignedByteType;
|
||||||
|
texture1.generateMipmaps = true;
|
||||||
texture1.needsUpdate = true;
|
texture1.needsUpdate = true;
|
||||||
return texture1;
|
return texture1;
|
||||||
}
|
}
|
||||||
_buildTriangles(width, height, size = 1, extent) {
|
_buildTriangles(width, height, size = 2, extent) {
|
||||||
// const extent = [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ]
|
// const extent = [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ]
|
||||||
const indices = [];
|
const indices = [];
|
||||||
const vertices = [];
|
const vertices = [];
|
||||||
|
|
|
@ -1,276 +0,0 @@
|
||||||
import BufferBase from './bufferBase';
|
|
||||||
import { getJSON } from '../../util/ajax';
|
|
||||||
import * as THREE from '../../core/three';
|
|
||||||
import TinySDF from '@mapbox/tiny-sdf';
|
|
||||||
|
|
||||||
import Global from '../../global';
|
|
||||||
const Space = 1;
|
|
||||||
export default class TextBuffer extends BufferBase {
|
|
||||||
|
|
||||||
geometryBuffer() {
|
|
||||||
this.metrics = {
|
|
||||||
buffer: 3,
|
|
||||||
family: 'ios9',
|
|
||||||
size: 24
|
|
||||||
};
|
|
||||||
const layerData = this.get('layerData');
|
|
||||||
const { textOffset = [ 0, 0 ] } = this.get('style');
|
|
||||||
const chars = [];
|
|
||||||
const textChars = {};
|
|
||||||
layerData.forEach(element => {
|
|
||||||
let text = element.shape || '';
|
|
||||||
text = text.toString();
|
|
||||||
for (let j = 0; j < text.length; j++) {
|
|
||||||
const code = text.charCodeAt(j);
|
|
||||||
textChars[text] = 0;
|
|
||||||
if (chars.indexOf(code) === -1) {
|
|
||||||
chars.push(text.charCodeAt(j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const sdfTexture = this._updateSdf(Object.keys(textChars).join(''));
|
|
||||||
this.sdfTexture = sdfTexture;
|
|
||||||
|
|
||||||
this._loadTextInfo(chars);
|
|
||||||
this.on('SourceLoaded', () => {
|
|
||||||
const textureElements = [];
|
|
||||||
const colors = [];
|
|
||||||
const originPoints = [];
|
|
||||||
const textSizes = [];
|
|
||||||
const textOffsets = [];
|
|
||||||
layerData.forEach(element => {
|
|
||||||
const size = element.size;
|
|
||||||
const pos = element.coordinates;
|
|
||||||
// const pen = { x: pos[0] - dimensions.advance / 2, y: pos[1] };
|
|
||||||
const pen = { x: textOffset[0], y: textOffset[1] };
|
|
||||||
let text = element.shape || '';
|
|
||||||
text = text.toString();
|
|
||||||
for (let i = 0; i < text.length; i++) {
|
|
||||||
|
|
||||||
|
|
||||||
const color = element.color;
|
|
||||||
this._drawGlyph(pos, text[i], pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.bufferStruct.style = layerData;
|
|
||||||
this.attributes = {
|
|
||||||
originPoints,
|
|
||||||
textSizes,
|
|
||||||
textOffsets,
|
|
||||||
colors,
|
|
||||||
textureElements
|
|
||||||
};
|
|
||||||
this.emit('completed');
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
_loadTextInfo(chars) {
|
|
||||||
getJSON({
|
|
||||||
url: `${Global.sdfHomeUrl}/getsdfdata?chars=${chars.join('|')}`
|
|
||||||
}, (e, info) => {
|
|
||||||
this.metrics.chars = info.info;
|
|
||||||
|
|
||||||
this._loadTextTexture(info.url);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_loadTextTexture(url) {
|
|
||||||
|
|
||||||
|
|
||||||
const img = new Image();
|
|
||||||
img.crossOrigin = 'anonymous';
|
|
||||||
|
|
||||||
|
|
||||||
img.onload = () => {
|
|
||||||
this.bufferStruct.textTexture = this._creatTexture(this.sdfTexture.texure);
|
|
||||||
this.emit('SourceLoaded');
|
|
||||||
};
|
|
||||||
img.src = url;
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 计算每个标注词语的位置
|
|
||||||
* @param {*} pos 文字三维空间坐标
|
|
||||||
* @param {*} text 字符
|
|
||||||
* @param {*} pen 字符在词语的偏移量
|
|
||||||
* @param {*} size 字体大小
|
|
||||||
* @param {*} colors 颜色
|
|
||||||
* @param {*} textureElements 纹理坐标
|
|
||||||
* @param {*} originPoints 初始位置数据
|
|
||||||
* @param {*} textSizes 文字大小数组
|
|
||||||
* @param {*} textOffsets 字体偏移量数据
|
|
||||||
* @param {*} color 文字颜色
|
|
||||||
*/
|
|
||||||
_drawGlyph(pos, text, pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color) {
|
|
||||||
const metrics = this.metrics;
|
|
||||||
const chr = text.charCodeAt(0);
|
|
||||||
const metric = metrics.chars[chr];
|
|
||||||
if (!metric) return;
|
|
||||||
const info = this.sdfTexture.info;
|
|
||||||
const { x, y } = info[text];
|
|
||||||
const scale = size / metrics.size;
|
|
||||||
|
|
||||||
let width = 24; // metric[0];
|
|
||||||
let height = 24;// metric[1];
|
|
||||||
|
|
||||||
// const horiBearingX = metric[2];
|
|
||||||
// const horiBearingY = metric[3];
|
|
||||||
|
|
||||||
// const horiAdvance = metric[4];
|
|
||||||
// const posX = metric[5];
|
|
||||||
// const posY = metric[6];
|
|
||||||
const posX = x;
|
|
||||||
const posY = y;
|
|
||||||
|
|
||||||
const buffer = metrics.buffer;
|
|
||||||
|
|
||||||
if (width > 0 && height > 0) {
|
|
||||||
width += buffer * 2;
|
|
||||||
height += buffer * 2;
|
|
||||||
|
|
||||||
// Add a quad (= two triangles) per glyph.
|
|
||||||
// const originX = (horiBearingX - buffer + width / 2) * scale;
|
|
||||||
// const originY = -(height - horiBearingY) * scale;
|
|
||||||
const originX = 0;
|
|
||||||
const originY = 0;
|
|
||||||
|
|
||||||
// const offsetWidth = width / 2 * scale / (1.0 - horiBearingX * 1.5 / horiAdvance);
|
|
||||||
// const offsetHeight = (horiAdvance / 2) * scale;
|
|
||||||
|
|
||||||
// const offsetWidth = width/2 * scale;
|
|
||||||
// const offsetHeight = height / 2 * scale;
|
|
||||||
// const offsetHeight = height * scale;
|
|
||||||
|
|
||||||
const offsetX = pen.x;
|
|
||||||
const offsetY = pen.y;
|
|
||||||
originPoints.push(
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
pos[0] + originX, pos[1] + originY, 0,
|
|
||||||
);
|
|
||||||
|
|
||||||
// textSizes.push(
|
|
||||||
// offsetWidth, offsetHeight,
|
|
||||||
// -offsetWidth, offsetHeight,
|
|
||||||
// -offsetWidth, -offsetHeight,
|
|
||||||
// offsetWidth, offsetHeight,
|
|
||||||
// -offsetWidth, -offsetHeight,
|
|
||||||
// offsetWidth, -offsetHeight,
|
|
||||||
// );
|
|
||||||
const bx = 0;
|
|
||||||
const by = metrics.size / 2 + buffer;
|
|
||||||
textSizes.push(
|
|
||||||
|
|
||||||
|
|
||||||
((bx - buffer + width) * scale), (height - by) * scale,
|
|
||||||
((bx - buffer) * scale), (height - by) * scale,
|
|
||||||
((bx - buffer) * scale), -by * scale,
|
|
||||||
|
|
||||||
((bx - buffer + width) * scale), (height - by) * scale,
|
|
||||||
((bx - buffer) * scale), -by * scale,
|
|
||||||
((bx - buffer + width) * scale), -by * scale,
|
|
||||||
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
textOffsets.push(
|
|
||||||
offsetX, offsetY,
|
|
||||||
offsetX, offsetY,
|
|
||||||
offsetX, offsetY,
|
|
||||||
offsetX, offsetY,
|
|
||||||
offsetX, offsetY,
|
|
||||||
offsetX, offsetY,
|
|
||||||
);
|
|
||||||
|
|
||||||
colors.push(
|
|
||||||
...color,
|
|
||||||
...color,
|
|
||||||
...color,
|
|
||||||
...color,
|
|
||||||
...color,
|
|
||||||
...color,
|
|
||||||
);
|
|
||||||
textureElements.push(
|
|
||||||
|
|
||||||
posX + width, posY,
|
|
||||||
posX, posY,
|
|
||||||
posX, posY + height,
|
|
||||||
|
|
||||||
posX + width, posY,
|
|
||||||
posX, posY + height,
|
|
||||||
posX + width, posY + height
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pen.x = pen.x + (horiAdvance + Space) * scale;
|
|
||||||
pen.x = pen.x + size * 1.8;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_measureText(text, size) {
|
|
||||||
const dimensions = {
|
|
||||||
advance: 0
|
|
||||||
};
|
|
||||||
const metrics = this.metrics;
|
|
||||||
const scale = size / metrics.size;
|
|
||||||
for (let i = 0; i < text.length; i++) {
|
|
||||||
const code = text.charCodeAt(i);
|
|
||||||
const horiAdvance = metrics.chars[code][4];
|
|
||||||
|
|
||||||
dimensions.advance += (horiAdvance + Space) * scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dimensions;
|
|
||||||
}
|
|
||||||
_creatTexture(image) {
|
|
||||||
this.bufferStruct.textSize = [ image.width, image.height ];
|
|
||||||
const texture = new THREE.Texture(image);
|
|
||||||
texture.minFilter = THREE.LinearFilter;
|
|
||||||
texture.magFilter = THREE.ClampToEdgeWrapping;
|
|
||||||
texture.needsUpdate = true;
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
_updateSdf(chars) {
|
|
||||||
const canvas = document.createElement('canvas');
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
const sdfs = {};
|
|
||||||
|
|
||||||
|
|
||||||
const fontSize = 24;
|
|
||||||
const fontWeight = 100;
|
|
||||||
const buffer = fontSize / 8;
|
|
||||||
const radius = fontSize / 3;
|
|
||||||
const canvasSize = Math.floor(Math.pow(chars.length, 0.5)) * (fontSize + buffer + radius);
|
|
||||||
canvas.width = canvasSize;
|
|
||||||
canvas.height = canvasSize;
|
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
const sdf = new TinySDF(fontSize, buffer, radius, null, null, fontWeight);
|
|
||||||
for (let y = 0, i = 0; y + sdf.size <= canvas.height && i < chars.length; y += sdf.size) {
|
|
||||||
for (let x = 0; x + sdf.size <= canvas.width && i < chars.length; x += sdf.size) {
|
|
||||||
ctx.putImageData(this._makeRGBAImageData(ctx, sdf.draw(chars[i]), sdf.size), x, y);
|
|
||||||
sdfs[chars[i]] = { x, y };
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
info: sdfs,
|
|
||||||
texure: canvas
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_makeRGBAImageData(ctx, alphaChannel, size) {
|
|
||||||
const imageData = ctx.createImageData(size, size);
|
|
||||||
const data = imageData.data;
|
|
||||||
for (let i = 0; i < alphaChannel.length; i++) {
|
|
||||||
data[4 * i + 0] = alphaChannel[i];
|
|
||||||
data[4 * i + 1] = alphaChannel[i];
|
|
||||||
data[4 * i + 2] = alphaChannel[i];
|
|
||||||
data[4 * i + 3] = 255;
|
|
||||||
}
|
|
||||||
return imageData;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,18 +19,18 @@ export default function extrudePolygon(points, extrude) {
|
||||||
const flattengeo = earcut.flatten(points);
|
const flattengeo = earcut.flatten(points);
|
||||||
const positions = [];
|
const positions = [];
|
||||||
let cells = [];
|
let cells = [];
|
||||||
|
const { dimensions } = flattengeo;
|
||||||
const triangles = earcut(flattengeo.vertices, flattengeo.holes, flattengeo.dimensions);
|
const triangles = earcut(flattengeo.vertices, flattengeo.holes, flattengeo.dimensions);
|
||||||
cells = triangles;
|
cells = triangles;
|
||||||
|
|
||||||
const pointCount = flattengeo.vertices.length / 3;
|
const pointCount = flattengeo.vertices.length / dimensions;
|
||||||
const { vertices } = flattengeo;
|
const { vertices } = flattengeo;
|
||||||
extrude ? full() : flat();
|
extrude ? full() : flat();
|
||||||
|
|
||||||
|
|
||||||
function flat() {
|
function flat() {
|
||||||
for (let i = 0; i < pointCount; i++) {
|
for (let i = 0; i < pointCount; i++) {
|
||||||
positions.push([ vertices[ i * 3 ], vertices[i * 3 + 1 ], 0 ]);
|
positions.push([ vertices[ i * dimensions ], vertices[i * dimensions + 1 ], 0 ]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function full() {
|
function full() {
|
||||||
|
@ -41,10 +41,10 @@ export default function extrudePolygon(points, extrude) {
|
||||||
// 顶部坐标
|
// 顶部坐标
|
||||||
|
|
||||||
for (let i = 0; i < pointCount; i++) {
|
for (let i = 0; i < pointCount; i++) {
|
||||||
positions.push([ vertices[ i * 3 ], vertices[i * 3 + 1 ], 1 ]);
|
positions.push([ vertices[ i * dimensions ], vertices[i * dimensions + 1 ], 1 ]);
|
||||||
}
|
}
|
||||||
for (let i = 0; i < pointCount; i++) {
|
for (let i = 0; i < pointCount; i++) {
|
||||||
positions.push([ vertices[ i * 3 ], vertices[i * 3 + 1 ], 0 ]);
|
positions.push([ vertices[ i * dimensions ], vertices[i * dimensions + 1 ], 0 ]);
|
||||||
}
|
}
|
||||||
for (let i = 0; i < n; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
if (i === (n - 1)) {
|
if (i === (n - 1)) {
|
||||||
|
|
|
@ -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,110 +0,0 @@
|
||||||
import { UniformSemantic, DataType, RenderState, BlendFunc } from '@ali/r3-base';
|
|
||||||
import { Material, RenderTechnique } from '@ali/r3-material';
|
|
||||||
export function ArclineMaterial() {
|
|
||||||
const tech = requireGeometryTechnique();
|
|
||||||
const newMtl = new Material('MeshlineTech_mtl');
|
|
||||||
newMtl.technique = tech;
|
|
||||||
newMtl.setValue('segmentNumber', 50.0);
|
|
||||||
return newMtl;
|
|
||||||
}
|
|
||||||
|
|
||||||
function requireGeometryTechnique() {
|
|
||||||
// 顶点着色器
|
|
||||||
const VERT_SHADER = `
|
|
||||||
precision mediump float;
|
|
||||||
attribute vec3 a_position;
|
|
||||||
attribute vec3 a_color;
|
|
||||||
attribute vec4 a_instance;
|
|
||||||
uniform mat4 matModelViewProjection;
|
|
||||||
uniform float segmentNumber;
|
|
||||||
varying vec3 v_color;
|
|
||||||
|
|
||||||
float getSegmentRatio(float index) {
|
|
||||||
return smoothstep(0.0, 1.0, index / (segmentNumber - 1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
float paraboloid(vec2 source, vec2 target, float ratio) {
|
|
||||||
vec2 x = mix(source, target, ratio);
|
|
||||||
vec2 center = mix(source, target, 0.5);
|
|
||||||
float dSourceCenter = distance(source, center);
|
|
||||||
float dXCenter = distance(x, center);
|
|
||||||
return (dSourceCenter + dXCenter) * (dSourceCenter - dXCenter)*0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 getPos(vec2 source, vec2 target, float height, float segmentRatio) {
|
|
||||||
return vec3(
|
|
||||||
mix(source, target, segmentRatio),
|
|
||||||
sqrt(max(0.0, height))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 source = a_instance.rg;
|
|
||||||
vec2 target = a_instance.ba;
|
|
||||||
float segmentIndex = a_position.x;
|
|
||||||
float segmentRatio = getSegmentRatio(segmentIndex);
|
|
||||||
vec3 c1 = vec3(0.929,0.972,0.917);
|
|
||||||
vec3 c2 = vec3(0.062,0.325,0.603);
|
|
||||||
v_color = mix(c1, c2, segmentRatio);
|
|
||||||
float height = paraboloid(source, target, segmentRatio);
|
|
||||||
vec3 position = getPos(source,target,height,segmentRatio);
|
|
||||||
gl_Position = matModelViewProjection * vec4(position, 1.0);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
// 片元着色器
|
|
||||||
const FRAG_SHADER = `
|
|
||||||
precision mediump float;
|
|
||||||
varying vec3 v_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_FragColor = vec4(v_color,1.0);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Technique 配置信息
|
|
||||||
const cfg = {
|
|
||||||
attributes: {
|
|
||||||
a_position: {
|
|
||||||
name: 'a_position',
|
|
||||||
semantic: 'POSITION',
|
|
||||||
type: DataType.FLOAT_VEC3
|
|
||||||
},
|
|
||||||
a_color: {
|
|
||||||
name: 'a_color',
|
|
||||||
semantic: 'COLOR',
|
|
||||||
type: DataType.FLOAT_VEC3
|
|
||||||
},
|
|
||||||
a_instance: {
|
|
||||||
name: 'a_instance',
|
|
||||||
semantic: 'INSPOS',
|
|
||||||
type: DataType.FLOAT_VEC4
|
|
||||||
}
|
|
||||||
},
|
|
||||||
uniforms: {
|
|
||||||
matModelViewProjection: {
|
|
||||||
name: 'matModelViewProjection',
|
|
||||||
semantic: UniformSemantic.MODELVIEWPROJECTION,
|
|
||||||
type: DataType.FLOAT_MAT4
|
|
||||||
},
|
|
||||||
segmentNumber: {
|
|
||||||
name: 'segmentNumber',
|
|
||||||
type: DataType.FLOAT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 创建 Technique
|
|
||||||
const tech = new RenderTechnique('MeshlineTech');
|
|
||||||
tech.states = {
|
|
||||||
enable: [ RenderState.BLEND ],
|
|
||||||
functions: { blendFunc: [ BlendFunc.SRC_ALPHA, BlendFunc.ONE_MINUS_SRC_ALPHA ] }//
|
|
||||||
};
|
|
||||||
tech.isValid = true;
|
|
||||||
tech.uniforms = cfg.uniforms;
|
|
||||||
tech.attributes = cfg.attributes;
|
|
||||||
tech.vertexShader = VERT_SHADER;
|
|
||||||
tech.fragmentShader = FRAG_SHADER;
|
|
||||||
|
|
||||||
return tech;
|
|
||||||
}
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import Material from './material';
|
||||||
|
import { getModule, wrapUniforms } from '../../util/shaderModule';
|
||||||
|
import merge from '@antv/util/lib/deep-mix';
|
||||||
|
|
||||||
|
export default class CircleMaterial extends Material {
|
||||||
|
constructor(_uniforms, _defines, parameters) {
|
||||||
|
super(parameters);
|
||||||
|
const { vs, fs, uniforms } = getModule('circle');
|
||||||
|
this.uniforms = wrapUniforms(merge(uniforms, _uniforms));
|
||||||
|
this.defines = _defines;
|
||||||
|
this.type = 'CircleMaterial';
|
||||||
|
this.vertexShader = vs;
|
||||||
|
this.fragmentShader = fs;
|
||||||
|
this.transparent = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,5 @@
|
||||||
import grid_frag from '../shader/grid_frag.glsl';
|
|
||||||
import grid_vert from '../shader/grid_vert.glsl';
|
|
||||||
import Material from './material';
|
import Material from './material';
|
||||||
|
import { getModule } from '../../util/shaderModule';
|
||||||
|
|
||||||
export default class GridMaterial extends Material {
|
export default class GridMaterial extends Material {
|
||||||
getDefaultParameters() {
|
getDefaultParameters() {
|
||||||
return {
|
return {
|
||||||
|
@ -11,7 +8,9 @@ export default class GridMaterial extends Material {
|
||||||
u_time: { value: 0 },
|
u_time: { value: 0 },
|
||||||
u_xOffset: { value: 0.01 },
|
u_xOffset: { value: 0.01 },
|
||||||
u_yOffset: { value: 0.01 },
|
u_yOffset: { value: 0.01 },
|
||||||
u_coverage: { value: 0.8 }
|
u_coverage: { value: 0.8 },
|
||||||
|
u_activeId: { value: 0 },
|
||||||
|
u_activeColor: { value: [ 1.0, 0, 0, 1.0 ] }
|
||||||
},
|
},
|
||||||
defines: {
|
defines: {
|
||||||
|
|
||||||
|
@ -21,11 +20,12 @@ export default class GridMaterial extends Material {
|
||||||
constructor(_uniforms, _defines, parameters) {
|
constructor(_uniforms, _defines, parameters) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
const { uniforms, defines } = this.getDefaultParameters();
|
const { uniforms, defines } = this.getDefaultParameters();
|
||||||
|
const { vs, fs } = getModule('grid');
|
||||||
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
|
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
|
||||||
this.type = 'GridMaterial';
|
this.type = 'GridMaterial';
|
||||||
this.defines = Object.assign(defines, _defines);
|
this.defines = Object.assign(defines, _defines);
|
||||||
this.vertexShader = grid_vert;
|
this.vertexShader = vs;
|
||||||
this.fragmentShader = grid_frag;
|
this.fragmentShader = fs;
|
||||||
this.transparent = true;
|
this.transparent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
import * as THREE from '../../core/three';
|
||||||
|
import Material from './material';
|
||||||
|
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: {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
constructor(_uniforms, _defines = {}, parameters) {
|
||||||
|
super(parameters);
|
||||||
|
const { uniforms, defines } = this.getDefaultParameters();
|
||||||
|
const { vs, fs } = getModule('heatmap_color');
|
||||||
|
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
|
||||||
|
this.type = 'HeatmapColorizeMaterial';
|
||||||
|
this.defines = Object.assign(defines, _defines);
|
||||||
|
this.vertexShader = vs;
|
||||||
|
this.fragmentShader = fs;
|
||||||
|
this.transparent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HeatmapIntensityMaterial extends Material {
|
||||||
|
getDefaultParameters() {
|
||||||
|
return {
|
||||||
|
uniforms: {
|
||||||
|
u_intensity: { value: 10.0 },
|
||||||
|
u_zoom: { value: 4 },
|
||||||
|
u_radius: { value: 10 }
|
||||||
|
},
|
||||||
|
defines: {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
import grid_frag from '../shader/hexagon_frag.glsl';
|
|
||||||
import grid_vert from '../shader/hexagon_vert.glsl';
|
|
||||||
import Material from './material';
|
import Material from './material';
|
||||||
|
import { getModule } from '../../util/shaderModule';
|
||||||
|
|
||||||
export default class hexagonMaterial extends Material {
|
export default class hexagonMaterial extends Material {
|
||||||
getDefaultParameters() {
|
getDefaultParameters() {
|
||||||
return {
|
return {
|
||||||
|
@ -11,7 +8,9 @@ export default class hexagonMaterial extends Material {
|
||||||
u_time: { value: 0 },
|
u_time: { value: 0 },
|
||||||
u_radius: { value: 0.01 },
|
u_radius: { value: 0.01 },
|
||||||
u_angle: { value: 0.01 },
|
u_angle: { value: 0.01 },
|
||||||
u_coverage: { value: 0.8 }
|
u_coverage: { value: 0.8 },
|
||||||
|
u_activeId: { value: 0 },
|
||||||
|
u_activeColor: { value: [ 1.0, 0, 0, 1.0 ] }
|
||||||
},
|
},
|
||||||
defines: {
|
defines: {
|
||||||
|
|
||||||
|
@ -21,11 +20,12 @@ export default class hexagonMaterial extends Material {
|
||||||
constructor(_uniforms, _defines, parameters) {
|
constructor(_uniforms, _defines, parameters) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
const { uniforms, defines } = this.getDefaultParameters();
|
const { uniforms, defines } = this.getDefaultParameters();
|
||||||
|
const { vs, fs } = getModule('hexagon');
|
||||||
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
|
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
|
||||||
this.type = 'hexagonMaterial';
|
this.type = 'hexagonMaterial';
|
||||||
this.defines = Object.assign(defines, _defines);
|
this.defines = Object.assign(defines, _defines);
|
||||||
this.vertexShader = grid_vert;
|
this.vertexShader = vs;
|
||||||
this.fragmentShader = grid_frag;
|
this.fragmentShader = fs;
|
||||||
this.transparent = true;
|
this.transparent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|