Mapbox 自定义图层 WebGL
Mapbox Custom Layer WebGL
我想知道如何在 Mapbox GL JS 中切换 webgl 层。
当我在下面的例子中调用 console.log(map.getStyle())
时。新的自定义层(突出显示)没有显示,所以我无法在调用 map.removeLayer('highlight')
时删除该层。然而,该图层确实出现在 console.log(map.style.sourceCaches)
中
我不确定如何删除图层以创建切换按钮。我查看了 Mapbox 文档。这可能很简单,但我就是不明白...
此外,有没有办法控制自定义纹理层的不透明度?
<html>
<head>
<meta charset="utf-8" />
<title>Add a custom style layer</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoia29ycmlhIiwiYSI6ImNpeHdpeHR5aDAwMjQycXFxcDZ2amQ2cjIifQ.mMba8iFMCiuoL7hOmfKjwQ';
var map = (window.map = new mapboxgl.Map({
container: 'map',
zoom: 3,
center: [7.5, 58],
style: 'mapbox://styles/mapbox/light-v10',
antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased
}));
// create a custom style layer to implement the WebGL content
var highlightLayer = {
id: 'highlight',
type: 'custom',
// method called when the layer is added to the map
// https://docs.mapbox.com/mapbox-gl-js/api/#styleimageinterface#onadd
onAdd: function (map, gl) {
// create GLSL source for vertex shader
var vertexSource =
'' +
'uniform mat4 u_matrix;' +
'attribute vec2 a_pos;' +
'void main() {' +
' gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0);' +
'}';
// create GLSL source for fragment shader
var fragmentSource =
'' +
'void main() {' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);' +
'}';
// create a vertex shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
// create a fragment shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);
// link the two shaders into a WebGL program
this.program = gl.createProgram();
gl.attachShader(this.program, vertexShader);
gl.attachShader(this.program, fragmentShader);
gl.linkProgram(this.program);
this.aPos = gl.getAttribLocation(this.program, 'a_pos');
// define vertices of the triangle to be rendered in the custom style layer
var helsinki = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 25.004,
lat: 60.239
});
var berlin = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 13.403,
lat: 52.562
});
var kyiv = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 30.498,
lat: 50.541
});
// create and initialize a WebGLBuffer to store vertex and color data
this.buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
helsinki.x,
helsinki.y,
berlin.x,
berlin.y,
kyiv.x,
kyiv.y
]),
gl.STATIC_DRAW
);
},
// method fired on each animation frame
// https://docs.mapbox.com/mapbox-gl-js/api/#map.event:render
render: function (gl, matrix) {
gl.useProgram(this.program);
gl.uniformMatrix4fv(
gl.getUniformLocation(this.program, 'u_matrix'),
false,
matrix
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
gl.enableVertexAttribArray(this.aPos);
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 0, 0);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3);
}
};
// add the custom style layer to the map
map.on('load', function () {
map.addLayer(highlightLayer, 'building');
});
</script>
</body>
</html>
基本上你需要将图层可见性设置为none
,所以图层将停止渲染:
map.setLayoutProperty('highlight', 'visibility', 'none');
自定义层(基于 CustomLayerInterface
)有一个警告,即尽管它们是可见的,但默认情况下它们没有可见性预设,因此您必须将其明确设置为可见首先,在 map.addLayer
创建之后。然后您可以使用相同的方法将图层从 visible
切换到 none
到 setLayoutProperty
。
在您的代码中添加一个 link 按钮和方法将像 this fiddle I have drafted with your sample 一样工作。
代码如下...
<html>
<head>
<meta charset="utf-8" />
<title>Add a custom style layer</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
#menu {
background: #fff;
position: absolute;
z-index: 1;
top: 10px;
right: 10px;
border-radius: 3px;
width: 120px;
border: 1px solid rgba(0, 0, 0, 0.4);
font-family: 'Open Sans', sans-serif;
}
#menu a {
font-size: 13px;
color: #404040;
display: block;
margin: 0;
padding: 0;
padding: 10px;
text-decoration: none;
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
text-align: center;
}
#menu a:last-child {
border: none;
}
#menu a:hover {
background-color: #f8f8f8;
color: #404040;
}
#menu a.active {
background-color: #3887be;
color: #ffffff;
}
#menu a.active:hover {
background: #3074a4;
}
</style>
</head>
<body>
<div id="map"></div>
<nav id="menu">
<a href="#" class="active" onclick="toggleLayer(this)">highlight</a>
</nav>
<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoia29ycmlhIiwiYSI6ImNpeHdpeHR5aDAwMjQycXFxcDZ2amQ2cjIifQ.mMba8iFMCiuoL7hOmfKjwQ';
var map = (window.map = new mapboxgl.Map({
container: 'map',
zoom: 3,
center: [7.5, 58],
style: 'mapbox://styles/mapbox/light-v10',
antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased
}));
// create a custom style layer to implement the WebGL content
var highlightLayer = {
id: 'highlight',
type: 'custom',
// method called when the layer is added to the map
// https://docs.mapbox.com/mapbox-gl-js/api/#styleimageinterface#onadd
onAdd: function (map, gl) {
// create GLSL source for vertex shader
var vertexSource =
'' +
'uniform mat4 u_matrix;' +
'attribute vec2 a_pos;' +
'void main() {' +
' gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0);' +
'}';
// create GLSL source for fragment shader
var fragmentSource =
'' +
'void main() {' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);' +
'}';
// create a vertex shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
// create a fragment shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);
// link the two shaders into a WebGL program
this.program = gl.createProgram();
gl.attachShader(this.program, vertexShader);
gl.attachShader(this.program, fragmentShader);
gl.linkProgram(this.program);
this.aPos = gl.getAttribLocation(this.program, 'a_pos');
// define vertices of the triangle to be rendered in the custom style layer
var helsinki = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 25.004,
lat: 60.239
});
var berlin = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 13.403,
lat: 52.562
});
var kyiv = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 30.498,
lat: 50.541
});
// create and initialize a WebGLBuffer to store vertex and color data
this.buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
helsinki.x,
helsinki.y,
berlin.x,
berlin.y,
kyiv.x,
kyiv.y
]),
gl.STATIC_DRAW
);
},
// method fired on each animation frame
// https://docs.mapbox.com/mapbox-gl-js/api/#map.event:render
render: function (gl, matrix) {
gl.useProgram(this.program);
gl.uniformMatrix4fv(
gl.getUniformLocation(this.program, 'u_matrix'),
false,
matrix
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
gl.enableVertexAttribArray(this.aPos);
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 0, 0);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3);
}
};
// add the custom style layer to the map
map.on('load', function () {
map.addLayer(highlightLayer, 'building');
map.setLayoutProperty('highlight', 'visibility', 'visible');
});
function toggleLayer(e) {
var clickedLayer = e.textContent;
var visibility = map.getLayoutProperty(clickedLayer, 'visibility');
// toggle layer visibility by changing the layout object's visibility property
if (visibility === 'visible') {
map.setLayoutProperty(clickedLayer, 'visibility', 'none');
this.className = '';
} else {
this.className = 'active';
map.setLayoutProperty(clickedLayer, 'visibility', 'visible');
}
}
</script>
</body>
</html>
如果这个答案解决了您的问题,请将其标记为已接受答案,这样它也会帮助其他用户知道这是正确的解决方案。
我想知道如何在 Mapbox GL JS 中切换 webgl 层。
当我在下面的例子中调用 console.log(map.getStyle())
时。新的自定义层(突出显示)没有显示,所以我无法在调用 map.removeLayer('highlight')
时删除该层。然而,该图层确实出现在 console.log(map.style.sourceCaches)
我不确定如何删除图层以创建切换按钮。我查看了 Mapbox 文档。这可能很简单,但我就是不明白...
此外,有没有办法控制自定义纹理层的不透明度?
<html>
<head>
<meta charset="utf-8" />
<title>Add a custom style layer</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoia29ycmlhIiwiYSI6ImNpeHdpeHR5aDAwMjQycXFxcDZ2amQ2cjIifQ.mMba8iFMCiuoL7hOmfKjwQ';
var map = (window.map = new mapboxgl.Map({
container: 'map',
zoom: 3,
center: [7.5, 58],
style: 'mapbox://styles/mapbox/light-v10',
antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased
}));
// create a custom style layer to implement the WebGL content
var highlightLayer = {
id: 'highlight',
type: 'custom',
// method called when the layer is added to the map
// https://docs.mapbox.com/mapbox-gl-js/api/#styleimageinterface#onadd
onAdd: function (map, gl) {
// create GLSL source for vertex shader
var vertexSource =
'' +
'uniform mat4 u_matrix;' +
'attribute vec2 a_pos;' +
'void main() {' +
' gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0);' +
'}';
// create GLSL source for fragment shader
var fragmentSource =
'' +
'void main() {' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);' +
'}';
// create a vertex shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
// create a fragment shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);
// link the two shaders into a WebGL program
this.program = gl.createProgram();
gl.attachShader(this.program, vertexShader);
gl.attachShader(this.program, fragmentShader);
gl.linkProgram(this.program);
this.aPos = gl.getAttribLocation(this.program, 'a_pos');
// define vertices of the triangle to be rendered in the custom style layer
var helsinki = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 25.004,
lat: 60.239
});
var berlin = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 13.403,
lat: 52.562
});
var kyiv = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 30.498,
lat: 50.541
});
// create and initialize a WebGLBuffer to store vertex and color data
this.buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
helsinki.x,
helsinki.y,
berlin.x,
berlin.y,
kyiv.x,
kyiv.y
]),
gl.STATIC_DRAW
);
},
// method fired on each animation frame
// https://docs.mapbox.com/mapbox-gl-js/api/#map.event:render
render: function (gl, matrix) {
gl.useProgram(this.program);
gl.uniformMatrix4fv(
gl.getUniformLocation(this.program, 'u_matrix'),
false,
matrix
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
gl.enableVertexAttribArray(this.aPos);
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 0, 0);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3);
}
};
// add the custom style layer to the map
map.on('load', function () {
map.addLayer(highlightLayer, 'building');
});
</script>
</body>
</html>
基本上你需要将图层可见性设置为none
,所以图层将停止渲染:
map.setLayoutProperty('highlight', 'visibility', 'none');
自定义层(基于 CustomLayerInterface
)有一个警告,即尽管它们是可见的,但默认情况下它们没有可见性预设,因此您必须将其明确设置为可见首先,在 map.addLayer
创建之后。然后您可以使用相同的方法将图层从 visible
切换到 none
到 setLayoutProperty
。
在您的代码中添加一个 link 按钮和方法将像 this fiddle I have drafted with your sample 一样工作。
代码如下...
<html>
<head>
<meta charset="utf-8" />
<title>Add a custom style layer</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
#menu {
background: #fff;
position: absolute;
z-index: 1;
top: 10px;
right: 10px;
border-radius: 3px;
width: 120px;
border: 1px solid rgba(0, 0, 0, 0.4);
font-family: 'Open Sans', sans-serif;
}
#menu a {
font-size: 13px;
color: #404040;
display: block;
margin: 0;
padding: 0;
padding: 10px;
text-decoration: none;
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
text-align: center;
}
#menu a:last-child {
border: none;
}
#menu a:hover {
background-color: #f8f8f8;
color: #404040;
}
#menu a.active {
background-color: #3887be;
color: #ffffff;
}
#menu a.active:hover {
background: #3074a4;
}
</style>
</head>
<body>
<div id="map"></div>
<nav id="menu">
<a href="#" class="active" onclick="toggleLayer(this)">highlight</a>
</nav>
<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoia29ycmlhIiwiYSI6ImNpeHdpeHR5aDAwMjQycXFxcDZ2amQ2cjIifQ.mMba8iFMCiuoL7hOmfKjwQ';
var map = (window.map = new mapboxgl.Map({
container: 'map',
zoom: 3,
center: [7.5, 58],
style: 'mapbox://styles/mapbox/light-v10',
antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased
}));
// create a custom style layer to implement the WebGL content
var highlightLayer = {
id: 'highlight',
type: 'custom',
// method called when the layer is added to the map
// https://docs.mapbox.com/mapbox-gl-js/api/#styleimageinterface#onadd
onAdd: function (map, gl) {
// create GLSL source for vertex shader
var vertexSource =
'' +
'uniform mat4 u_matrix;' +
'attribute vec2 a_pos;' +
'void main() {' +
' gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0);' +
'}';
// create GLSL source for fragment shader
var fragmentSource =
'' +
'void main() {' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);' +
'}';
// create a vertex shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
// create a fragment shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);
// link the two shaders into a WebGL program
this.program = gl.createProgram();
gl.attachShader(this.program, vertexShader);
gl.attachShader(this.program, fragmentShader);
gl.linkProgram(this.program);
this.aPos = gl.getAttribLocation(this.program, 'a_pos');
// define vertices of the triangle to be rendered in the custom style layer
var helsinki = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 25.004,
lat: 60.239
});
var berlin = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 13.403,
lat: 52.562
});
var kyiv = mapboxgl.MercatorCoordinate.fromLngLat({
lng: 30.498,
lat: 50.541
});
// create and initialize a WebGLBuffer to store vertex and color data
this.buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
helsinki.x,
helsinki.y,
berlin.x,
berlin.y,
kyiv.x,
kyiv.y
]),
gl.STATIC_DRAW
);
},
// method fired on each animation frame
// https://docs.mapbox.com/mapbox-gl-js/api/#map.event:render
render: function (gl, matrix) {
gl.useProgram(this.program);
gl.uniformMatrix4fv(
gl.getUniformLocation(this.program, 'u_matrix'),
false,
matrix
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
gl.enableVertexAttribArray(this.aPos);
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 0, 0);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3);
}
};
// add the custom style layer to the map
map.on('load', function () {
map.addLayer(highlightLayer, 'building');
map.setLayoutProperty('highlight', 'visibility', 'visible');
});
function toggleLayer(e) {
var clickedLayer = e.textContent;
var visibility = map.getLayoutProperty(clickedLayer, 'visibility');
// toggle layer visibility by changing the layout object's visibility property
if (visibility === 'visible') {
map.setLayoutProperty(clickedLayer, 'visibility', 'none');
this.className = '';
} else {
this.className = 'active';
map.setLayoutProperty(clickedLayer, 'visibility', 'visible');
}
}
</script>
</body>
</html>
如果这个答案解决了您的问题,请将其标记为已接受答案,这样它也会帮助其他用户知道这是正确的解决方案。