maptalks 开发GIS地图(12)maptalks.three.05 bar-music

1. 说明

使用柱状图,并根据音乐节奏显示动画效果。

 

2. 初始化地图

 1 var map = new maptalks.Map("map", {
 2             center: [120.88083857368815, 31.494732837748273],
 3             zoom: 10,
 4             pitch: 35,
 5             bearing: -43.600000000000136,
 6 
 7             centerCross: true,
 8             doubleClickZoom: false,
 9             // baseLayer: new maptalks.TileLayer('tile', {
10             //     urlTemplate: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
11             //     subdomains: ['a', 'b', 'c', 'd'],
12             //     attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>'
13             // })
14         });

 

3. 添加threelayer 图层,并设置环境。

其中 oReq 对象读取 MP3文件的数据,并进行解析。

 1  // the ThreeLayer to draw
 2         var threeLayer = new maptalks.ThreeLayer('t', {
 3             forceRenderOnMoving: true,
 4             forceRenderOnRotating: true
 5             // animation: true
 6         });
 7         threeLayer.prepareToDraw = function (gl, scene, camera) {
 8             var light = new THREE.PointLight(0xffffff);
 9             // light.position.set(0, -10, 10).normalize();
10             camera.add(light);
11 
12             var ambientlight = new THREE.AmbientLight(0x999999, 1.57);
13             scene.add(ambientlight);
14 
15             var oReq = new XMLHttpRequest();
16             oReq.open('GET', './data/roll-it-up.mp3', true);
17             oReq.responseType = 'arraybuffer';
18 
19             oReq.onload = function (e) {
20                 audioContext.decodeAudioData(oReq.response, initVisualizer);
21             };
22             oReq.send();
23             // threeLayer.config('animation', true);
24             animation();
25         };
26 
27         threeLayer.addTo(map);

 

4. MP3数据解析

 1   // code from https://www.echartsjs.com/examples/zh/editor.html?c=bar3d-music-visualization&gl=1
 2         function initVisualizer(audioBuffer) {
 3             inited = true;
 4 
 5             var source = audioContext.createBufferSource();
 6             source.buffer = audioBuffer;
 7 
 8             // Must invoked right after click event
 9             if (source.noteOn) {
10                 source.noteOn(0);
11             } else {
12                 source.start(0);
13             }
14 
15             var analyzer = audioContext.createAnalyser();
16             var gainNode = audioContext.createGain();
17             analyzer.fftSize = 4096;
18 
19             gainNode.gain.value = 1;
20             source.connect(gainNode);
21             gainNode.connect(analyzer);
22             analyzer.connect(audioContext.destination);
23 
24             var frequencyBinCount = analyzer.frequencyBinCount;
25             var dataArray = new Uint8Array(frequencyBinCount);
26 
27 
28             function update() {
29                 analyzer.getByteFrequencyData(dataArray);
30 
31                 var item = [];
32                 var size = 50;
33                 var dataProvider = [];
34 
35                 for (var i = 0; i < size * size; i++) {
36                     var x = i % size;
37                     var y = Math.floor(i / size);
38                     var dx = x - size / 2;
39                     var dy = y - size / 2;
40 
41                     var angle = Math.atan2(dy, dx);
42                     if (angle < 0) {
43                         angle = Math.PI * 2 + angle;
44                     }
45                     var dist = Math.sqrt(dx * dx + dy * dy);
46                     var idx = Math.min(
47                         frequencyBinCount - 1, Math.round(angle / Math.PI / 2 * 60 + dist * 60) + 100
48                     );
49 
50                     var val = Math.pow(dataArray[idx] / 100, 3);
51                     dataProvider.push([x, y, Math.max(val, 0.1)]);
52                 }
53                 var musdata = [];
54                 for (var i = 0; i < dataProvider.length; i++) {
55                     var d = dataProvider[i];
56                     var x = d[0],
57                         y = d[1],
58                         z = d[2];
59                     var lng = minLng + x * averageLng;
60                     var lat = minLat + y * averageLat;
61                     var height = z * scale;
62                     if (height < 2000) continue;
63                     musdata.push({
64                         // name: Math.random() * 10000,
65                         value: [lng, lat, height]
66                     });
67                 }
68                 addBars(musdata);
69 
70                 setTimeout(update, UPDATE_DURATION);
71             }
72             update();
73         }

 

5. 更新数据柱状图

 1     function addBars(data) {
 2             if (bars) {
 3                 threeLayer.removeMesh(bars, false);
 4             }
 5             bars = data.map(function (d) {
 6                 var value = d.value;
 7                 minValue = Math.min(minValue, value[2]);
 8                 maxValue = Math.max(maxValue, value[2]);
 9                 const material = getMaterial(value[2]);
10                 if (!barCache[value[2]]) {
11                     barCache[value[2]] = threeLayer.toBox(value.slice(0, 2), {
12                         height: value[2],
13                         radius: 600,
14                         topColor: '#fff',
15                         interactive: false
16                     }, material);
17                 }
18                 //复用geometry
19                 const geometry = barCache[value[2]].getObject3d().geometry;
20                 const options = barCache[value[2]].getOptions();
21                 const coordinate = value.slice(0, 2);
22                 const bar = new maptalks.BaseObject();
23                 bar._initOptions(Object.assign({}, options, { coordinate }));
24                 bar._createMesh(geometry, material);
25                 const position = threeLayer.coordinateToVector3(coordinate);
26                 bar.getObject3d().position.copy(position);
27                 return bar;
28             });
29             threeLayer.addMesh(bars, false);
30         }

 

6. 显示效果

这个动画确实是根据音乐节奏来的, 音乐可参考 ../data/roll-it-up.mp3。

这让我想起了windowsXP自带的音乐播放器。

 

 

7. 源码参考

https://github.com/WhatGIS/maptalkMap

posted @ 2021-04-30 15:32  googlegis  阅读(350)  评论(0编辑  收藏  举报

坐标合肥,非典型GIS开发人员 GitHub