mapbox结合three实现添加3D模型并执行点击事件

点击事件

this.renderer.domElement.addEventListener( 'click', (e)=>{

            const { clientX ,clientY} = e
            const x = ( clientX  / window.innerWidth ) * 2 - 1;
            const y = ( clientY / window.innerHeight ) * 2 + 1;
            const mousePoint = new THREE.Vector2(x,y)
            const raycaster = new THREE.Raycaster();
            // 通过摄像机和鼠标位置更新射线
            raycaster.setFromCamera( mousePoint, this.camera );

            // 计算物体和射线的焦点
            const intersects = raycaster.intersectObjects( this.scene.children ,true );
            // todo 进行过滤
            console.log(intersects)
        } );

完整代码(在官网demo基础上修改):

<!DOCTYPE html>
<html>
<head>
	<meta charset='utf-8' />
	<title>添加3D模型</title>
	<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
	<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.1/mapbox-gl.js'></script>
	<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.1/mapbox-gl.css' rel='stylesheet' />
	<style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }
	</style>
</head>
<body>

<script src='https://unpkg.com/three@0.102.0/build/three.min.js'></script>
<script src="https://unpkg.com/three@0.102.0/examples/js/loaders/GLTFLoader.js"></script>
<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiZXhhbXBsZXMiLCJhIjoiY2p1dHRybDR5MGJuZjQzcGhrZ2doeGgwNyJ9.a-vxW4UaxOoUMWUTGnEArw'
var map = window.map = new mapboxgl.Map({
	container: 'map',
	style: 'mapbox://styles/mapbox/light-v10',
	zoom: 17.5,
	center: [108.962945, 34.270084],
	pitch: 60
});

// parameters to ensure the model is georeferenced correctly on the map
var modelOrigin = [108.962945, 34.270084];
var modelAltitude = 0;
var modelRotate = [Math.PI / 2, 0, 0];
var modelScale = 5.41843220338983e-8;

// transformation parameters to position, rotate and scale the 3D model onto the map
var modelTransform = {
	translateX: mapboxgl.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude).x,
	translateY: mapboxgl.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude).y,
	translateZ: mapboxgl.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude).z,
	rotateX: modelRotate[0],
	rotateY: modelRotate[1],
	rotateZ: modelRotate[2],
	scale: modelScale
};

var THREE = window.THREE;
// configuration of the custom layer for a 3D model per the CustomLayerInterface
var customLayer = {
	id: '3dmodel',
	type: 'custom',
	renderingMode: '3d',
	onAdd: function (map, gl) {
		this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
		this.scene = new THREE.Scene();

		// 两条光线
		var directionalLight = new THREE.DirectionalLight(0xffffff);
		directionalLight.position.set(0, -50, 100).normalize();
		this.scene.add(directionalLight);

		var directionalLight2 = new THREE.DirectionalLight(0xffffff);
		directionalLight2.position.set(0, 50, 100).normalize();
		this.scene.add(directionalLight2);

		// gltf加载器
		var loader = new THREE.GLTFLoader();
		loader.load('https://docs.mapbox.com/mapbox-gl-js/assets/34M_17/34M_17.gltf', (gltf) => {
			console.log(gltf)
			this.scene.add(gltf.scene);
		});
		this.map = map;
		// use the Mapbox GL JS map canvas for three.js
		this.renderer = new THREE.WebGLRenderer({
			canvas: this.map.getCanvas(),
			context: gl
		});
		this.renderer.autoClear = false;
		//在渲染时添加click事件
		this.renderer.domElement.addEventListener('click', (e) => {

			const { clientX, clientY } = e
			const x = (clientX / window.innerWidth) * 2 - 1;
			const y = (clientY / window.innerHeight) * 2 + 1;
			const mousePoint = new THREE.Vector2(x, y)
			const raycaster = new THREE.Raycaster();
			// 通过摄像机和鼠标位置更新射线
			raycaster.setFromCamera(mousePoint, this.camera);

			// 计算物体和射线的焦点
			const intersects = raycaster.intersectObjects(this.scene.children, true);
			recursion();
			console.log(intersects)
		});
	},
	render: function (gl, matrix) {
		var rotationX = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), modelTransform.rotateX);
		var rotationY = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0), modelTransform.rotateY);
		var rotationZ = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 0, 1), modelTransform.rotateZ);

		var m = new THREE.Matrix4().fromArray(matrix);
		var l = new THREE.Matrix4().makeTranslation(modelTransform.translateX, modelTransform.translateY, modelTransform.translateZ)
				.scale(new THREE.Vector3(modelTransform.scale, -modelTransform.scale, modelTransform.scale))
				.multiply(rotationX)
				.multiply(rotationY)
				.multiply(rotationZ);

		this.camera.projectionMatrix.elements = matrix;
		this.camera.projectionMatrix = m.multiply(l);

		this.renderer.state.reset();
		this.renderer.render(this.scene, this.camera);
		//渲染
		this.map.triggerRepaint();
	}
};

map.on('style.load', function () {
	map.addLayer(customLayer);
});

/**
 * 递归 过滤处理
 */
function recursion() {
	//do something
}

</script>

</body>
</html>

Mapbox 中,可以通过 `InfoWindowManager` 类来实现弹窗的显示和隐藏,以及弹窗的点击事件。要实现点击展开全部的功能,可以按照以下步骤进行: 1. 创建一个自定义的弹窗视图(也就是 InfoWindow),并在其中添加一个 `TextView` 用来显示内容,例如: ``` public class CustomInfoWindow implements InfoWindow { private final View view; private final TextView textView; public CustomInfoWindow(@NonNull LayoutInflater layoutInflater) { view = layoutInflater.inflate(R.layout.layout_info_window, null); textView = view.findViewById(R.id.tv_info_window_content); } @NonNull @Override public View getInfoWindow(@NonNull Marker marker) { textView.setText(marker.getTitle()); return view; } @NonNull @Override public View getInfoContents(@NonNull Marker marker) { return view; } @Override public void onClick(@NonNull Marker marker, @NonNull InfoWindowInteractionListener interactionListener) { // 点击弹窗时的逻辑 // 点击弹窗时展示全部内容 textView.setMaxLines(Integer.MAX_VALUE); interactionListener.onHide(); } @Override public void onClose(@NonNull Marker marker) { // 弹窗关闭时的逻辑 // 弹窗关闭时恢复原来的内容显示模式 textView.setMaxLines(2); } } ``` 在 `onClick` 方法中,我们将 `TextView` 的 `maxLines` 属性设置为 `Integer.MAX_VALUE`,这样就可以将内容全部展示出来。同时,我们还需要通过 `interactionListener.onHide()` 方法来隐藏弹窗,以便用户能够看到全部内容。 在 `onClose` 方法中,我们将 `TextView` 的 `maxLines` 属性重新设置为 2,以便在下次打开弹窗时能够正确展示内容。 2. 创建 `InfoWindowManager` 实例,并设置弹窗视图和弹窗点击事件,例如: ``` private InfoWindowManager infoWindowManager; private CustomInfoWindow customInfoWindow; // 在 onCreate 方法中初始化 InfoWindowManager 和 CustomInfoWindow infoWindowManager = new InfoWindowManager(mapView, mapboxMap); customInfoWindow = new CustomInfoWindow(getLayoutInflater()); infoWindowManager.setInfoWindowAdapter(new MapboxInfoWindowAdapter(this)); infoWindowManager.addClickListener(customInfoWindow); ``` 在这里,我们创建了 `InfoWindowManager` 实例,并将其与 `MapView` 和 `MapboxMap` 关联起来。然后,我们创建了 `CustomInfoWindow` 实例,并将其设置为弹窗视图。最后,我们将 `CustomInfoWindow` 的点击事件设置为弹窗点击事件。 3. 在需要显示弹窗的地方,调用 `InfoWindowManager` 的 `toggle()` 方法即可,例如: ``` Marker marker = mapboxMap.addMarker(new MarkerOptions().position(latLng).title("这是一个标题").snippet("这是一个内容")); infoWindowManager.toggle(marker, true); ``` 在这里,我们创建了一个标记,并将其与地图关联起来。然后,我们调用 `InfoWindowManager` 的 `toggle()` 方法来显示弹窗。 这样,就可以在 Mapbox实现弹窗的点击事件,点击展开全部了。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qlanto

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值