diff --git a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts index e0063858b..b88621bba 100644 --- a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts +++ b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts @@ -20,7 +20,11 @@ export class NodesChannelsMap implements OnInit, OnDestroy { @Input() publicKey: string | undefined; observable$: Observable; - center: number[] | undefined = undefined; + + center: number[] | undefined; + zoom: number | undefined; + channelWidth = 0.6; + channelOpacity = 0.1; chartInstance = undefined; chartOptions: EChartsOption = {}; @@ -42,7 +46,8 @@ export class NodesChannelsMap implements OnInit, OnDestroy { ngOnDestroy(): void {} ngOnInit(): void { - this.center = this.style === 'widget' ? [0, 0, -10] : undefined; + this.center = this.style === 'widget' ? [0, 40] : [0, 5]; + this.zoom = this.style === 'widget' ? 3.5 : 1.3; if (this.style === 'graph') { this.seoService.setTitle($localize`Lightning nodes channels world map`); @@ -69,29 +74,46 @@ export class NodesChannelsMap implements OnInit, OnDestroy { thisNodeGPS = [channel[6], channel[7]]; } - channelsLoc.push([[channel[2], channel[3]], [channel[6], channel[7]]]); + // We add a bit of noise so nodes at the same location are not all + // on top of each other + let random = Math.random() * 2 * Math.PI; + let random2 = Math.random() * 0.01; + if (!nodesPubkeys[channel[0]]) { - nodes.push({ - publicKey: channel[0], - name: channel[1], - value: [channel[2], channel[3]], - }); - nodesPubkeys[channel[0]] = true; + nodes.push([ + channel[2] + random2 * Math.cos(random), + channel[3] + random2 * Math.sin(random), + 1, + channel[0], + channel[1] + ]); + nodesPubkeys[channel[0]] = nodes[nodes.length - 1]; } + + random = Math.random() * 2 * Math.PI; + random2 = Math.random() * 0.01; + if (!nodesPubkeys[channel[4]]) { - nodes.push({ - publicKey: channel[4], - name: channel[5], - value: [channel[6], channel[7]], - }); - nodesPubkeys[channel[4]] = true; + nodes.push([ + channel[6] + random2 * Math.cos(random), + channel[7] + random2 * Math.sin(random), + 1, + channel[4], + channel[5] + ]); + nodesPubkeys[channel[4]] = nodes[nodes.length - 1]; } + + const channelLoc = []; + channelLoc.push(nodesPubkeys[channel[0]].slice(0, 2)); + channelLoc.push(nodesPubkeys[channel[4]].slice(0, 2)); + channelsLoc.push(channelLoc); } if (this.style === 'nodepage' && thisNodeGPS) { - // 1ML 0217890e3aad8d35bc054f43acc00084b25229ecff0ab68debd82883ad65ee8266 - // New York GPS [-74.0068, 40.7123] - // Map center [-20.55, 0, -9.85] - this.center = [thisNodeGPS[0] * -20.55 / -74.0068, 0, thisNodeGPS[1] * -9.85 / 40.7123]; + this.center = [thisNodeGPS[0], thisNodeGPS[1]]; + this.zoom = 10; + this.channelWidth = 1; + this.channelOpacity = 1; } this.prepareChartOptions(nodes, channelsLoc); @@ -115,87 +137,84 @@ export class NodesChannelsMap implements OnInit, OnDestroy { } this.chartOptions = { - silent: this.style === 'widget' ? true : false, + silent: this.style === 'widget', title: title ?? undefined, - geo3D: { - map: 'world', - shading: 'color', + tooltip: {}, + geo: { + animation: false, silent: true, - postEffect: { - enable: true, - bloom: { - intensity: 0.1, - } - }, - viewControl: { - center: this.center, - minDistance: 1, - maxDistance: 60, - distance: this.style === 'widget' ? 22 : this.style === 'nodepage' ? 22 : 60, - alpha: 90, - rotateSensitivity: 0, - panSensitivity: this.style === 'widget' ? 0 : 1, - zoomSensitivity: this.style === 'widget' ? 0 : 0.5, - panMouseButton: this.style === 'widget' ? null : 'left', - rotateMouseButton: undefined, + center: this.center, + zoom: this.zoom, + tooltip: { + show: true }, + map: 'world', + roam: this.style === 'widget' ? false : true, itemStyle: { - color: 'white', - opacity: 0.02, - borderWidth: 1, borderColor: 'black', + color: '#ffffff44' }, - regionHeight: 0.01, + scaleLimit: { + min: 1.3, + max: 100000, + } }, series: [ { - // @ts-ignore - type: 'lines3D', - coordinateSystem: 'geo3D', - blendMode: 'lighter', - lineStyle: { - width: 1, - opacity: ['widget', 'graph'].includes(this.style) ? 0.025 : 1, + large: true, + progressive: 200, + type: 'scatter', + data: nodes, + coordinateSystem: 'geo', + geoIndex: 0, + symbolSize: 4, + tooltip: { + backgroundColor: 'rgba(17, 19, 31, 1)', + borderRadius: 4, + shadowColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { + color: '#b1b1b1', + align: 'left', + }, + borderColor: '#000', + formatter: (value) => { + const data = value.data; + const alias = data[4].length > 0 ? data[4] : data[3].slice(0, 20); + return `${alias}`; + } }, - data: channels + itemStyle: { + color: 'white', + borderColor: 'black', + borderWidth: 2, + opacity: 1, + }, + blendMode: 'lighter', + zlevel: 1, }, { - // @ts-ignore - type: 'scatter3D', - symbol: 'circle', - blendMode: 'lighter', - coordinateSystem: 'geo3D', - symbolSize: 3, - itemStyle: { - color: '#BBFFFF', - opacity: 1, - borderColor: '#FFFFFF00', + large: true, + progressive: 200, + silent: true, + type: 'lines', + coordinateSystem: 'geo', + data: channels, + lineStyle: { + opacity: this.channelOpacity, + width: this.channelWidth, + curveness: 0, + color: '#466d9d', }, - data: nodes, - emphasis: { - label: { - position: 'top', - color: 'white', - fontSize: 16, - formatter: function(value) { - return value.name; - }, - show: true, - } - } - }, + blendMode: 'lighter', + tooltip: { + show: false, + }, + zlevel: 2, + } ] }; } - @HostListener('window:wheel', ['$event']) - onWindowScroll(e): void { - // Not very smooth when using the mouse - if (this.style === 'widget' && e.target.tagName === 'CANVAS') { - window.scrollBy({left: 0, top: e.deltaY, behavior: 'auto'}); - } - } - onChartInit(ec) { if (this.chartInstance !== undefined) { return; @@ -211,14 +230,34 @@ export class NodesChannelsMap implements OnInit, OnDestroy { }); }); } - + this.chartInstance.on('click', (e) => { - if (e.data && e.data.publicKey) { + if (e.data) { this.zone.run(() => { - const url = new RelativeUrlPipe(this.stateService).transform(`/lightning/node/${e.data.publicKey}`); + const url = new RelativeUrlPipe(this.stateService).transform(`/lightning/node/${e.data[3]}`); this.router.navigate([url]); }); } }); + + this.chartInstance.on('georoam', (e) => { + if (!e.zoom || this.style === 'nodepage') { + return; + } + + const speed = 0.005; + const chartOptions = { + series: this.chartOptions.series + }; + + chartOptions.series[1].lineStyle.opacity += e.zoom > 1 ? speed : -speed; + chartOptions.series[1].lineStyle.width += e.zoom > 1 ? speed : -speed; + chartOptions.series[0].symbolSize += e.zoom > 1 ? speed * 10 : -speed * 10; + chartOptions.series[1].lineStyle.opacity = Math.max(0.05, Math.min(0.5, chartOptions.series[1].lineStyle.opacity)); + chartOptions.series[1].lineStyle.width = Math.max(0.5, Math.min(1, chartOptions.series[1].lineStyle.width)); + chartOptions.series[0].symbolSize = Math.max(4, Math.min(5.5, chartOptions.series[0].symbolSize)); + + this.chartInstance.setOption(chartOptions); + }); } }