128 lines
3.1 KiB
Vue
128 lines
3.1 KiB
Vue
|
<template>
|
||
|
<div :id="id" class="world-map"></div>
|
||
|
</template>
|
||
|
<script>
|
||
|
import 'd3';
|
||
|
import * as d3 from 'd3';
|
||
|
import 'topojson';
|
||
|
import { throttle } from '@/util/throttle';
|
||
|
|
||
|
export default {
|
||
|
name: 'world-map',
|
||
|
props: {
|
||
|
mapData: {
|
||
|
type: Object,
|
||
|
default: () => ({})
|
||
|
},
|
||
|
points: {
|
||
|
type: Array,
|
||
|
default: () => []
|
||
|
}
|
||
|
},
|
||
|
data() {
|
||
|
return {
|
||
|
id: this.randomString(),
|
||
|
color1: '#f6f9fc',
|
||
|
color2: '#adb5bd',
|
||
|
highlightFillColor: '#ced4da',
|
||
|
borderColor: 'white',
|
||
|
highlightBorderColor: 'white',
|
||
|
bubbleHighlightFillColor: '#11cdef',
|
||
|
bubbleFillColor: '#fb6340'
|
||
|
};
|
||
|
},
|
||
|
methods: {
|
||
|
generateColors(length) {
|
||
|
return d3
|
||
|
.scaleLinear()
|
||
|
.domain([0, length])
|
||
|
.range([this.color1, this.color2]);
|
||
|
},
|
||
|
generateMapColors() {
|
||
|
let mapDataValues = Object.values(this.mapData);
|
||
|
let maxVal = Math.max(...mapDataValues);
|
||
|
let colors = this.generateColors(maxVal);
|
||
|
let mapData = {};
|
||
|
let fills = {
|
||
|
defaultFill: '#EDF0F2'
|
||
|
};
|
||
|
for (let key in this.mapData) {
|
||
|
let val = this.mapData[key];
|
||
|
fills[key] = colors(val);
|
||
|
mapData[key] = {
|
||
|
fillKey: key,
|
||
|
value: val
|
||
|
};
|
||
|
}
|
||
|
return {
|
||
|
mapData,
|
||
|
fills
|
||
|
};
|
||
|
},
|
||
|
async initVectorMap() {
|
||
|
let DataMap = await import('datamaps');
|
||
|
DataMap = DataMap.default || DataMap
|
||
|
let { fills, mapData } = this.generateMapColors();
|
||
|
let worldMap = new DataMap({
|
||
|
scope: 'world',
|
||
|
element: document.getElementById(this.id),
|
||
|
fills,
|
||
|
data: mapData,
|
||
|
responsive: true,
|
||
|
geographyConfig: {
|
||
|
borderColor: this.borderColor,
|
||
|
borderWidth: 1,
|
||
|
borderOpacity: 1,
|
||
|
highlightFillColor: this.highlightFillColor,
|
||
|
highlightBorderColor: this.highlightBorderColor,
|
||
|
highlightBorderWidth: 1,
|
||
|
highlightBorderOpacity: 1
|
||
|
}
|
||
|
});
|
||
|
let bubbleOptions = {
|
||
|
radius: 2,
|
||
|
borderWidth: 4,
|
||
|
highlightBorderWidth: 4,
|
||
|
fillKey: this.bubbleFillColor,
|
||
|
fillColor: this.bubbleFillColor,
|
||
|
borderColor: this.bubbleFillColor,
|
||
|
highlightFillColor: this.bubbleHighlightFillColor,
|
||
|
highlightBorderColor: this.bubbleHighlightFillColor
|
||
|
}
|
||
|
let bubblePoints = this.points.map(point => {
|
||
|
return {
|
||
|
...bubbleOptions,
|
||
|
...point
|
||
|
}
|
||
|
})
|
||
|
worldMap.bubbles(bubblePoints, {
|
||
|
popupTemplate: function(geo, data) {
|
||
|
return '<div class="hoverinfo">' + data.name
|
||
|
}
|
||
|
});
|
||
|
let resizeFunc = worldMap.resize.bind(worldMap);
|
||
|
window.addEventListener(
|
||
|
'resize',
|
||
|
() => {
|
||
|
throttle(resizeFunc, 40);
|
||
|
},
|
||
|
false
|
||
|
);
|
||
|
},
|
||
|
randomString() {
|
||
|
let text = "";
|
||
|
let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||
|
|
||
|
for (let i = 0; i < 5; i++)
|
||
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||
|
|
||
|
return text;
|
||
|
}
|
||
|
},
|
||
|
async mounted() {
|
||
|
this.initVectorMap();
|
||
|
}
|
||
|
};
|
||
|
</script>
|
||
|
<style></style>
|