208 lines
6.1 KiB
Vue
208 lines
6.1 KiB
Vue
<template>
|
|
<div>
|
|
|
|
<svg :class="svgClass" :width="width" :height="height">
|
|
|
|
<g style="transform: translate(2px, 2px)">
|
|
|
|
|
|
<g v-for="cinfo in countries"
|
|
:key="cinfo.country"
|
|
@mouseleave="overPoint('reset')"
|
|
>
|
|
<path :style="{stroke:cinfo.color}"
|
|
:d="calculatePath(cinfo.list)"
|
|
/>
|
|
|
|
<circle v-for="(point,i) in (cinfo.list)"
|
|
:key="'c'+i"
|
|
:style="{fill:cinfo.color}"
|
|
:cx="scales.x(new Date(point.date))"
|
|
:cy="scales.y(point[dataType])"
|
|
r="2"
|
|
/>
|
|
|
|
<circle v-for="(point,i) in (cinfo.list)"
|
|
opacity="0"
|
|
:key="'cinv'+i"
|
|
:cx="scales.x(new Date(point.date))"
|
|
:cy="scales.y(point[dataType])"
|
|
r="7"
|
|
@mouseover="overPoint(point,cinfo.color)"
|
|
/>
|
|
|
|
<rect :x="overpoint.x"
|
|
:y="overpoint.y-10"
|
|
:width=" (6+overpoint.text.toString().length) * 4"
|
|
:height="18"
|
|
/>
|
|
|
|
<text :x="overpoint.x+4"
|
|
:y="overpoint.y+4"
|
|
class="overpoint"
|
|
:style="{fill:overpoint.color}"
|
|
>
|
|
{{overpoint.text}}
|
|
</text>
|
|
|
|
</g>
|
|
|
|
<g class="axisg"></g>
|
|
</g>
|
|
</svg>
|
|
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
|
|
import {scaleLinear, scaleLog, scalePow, scaleTime} from 'd3';
|
|
import {axisLeft, axisBottom} from 'd3';
|
|
import {axisRight, axisTop} from 'd3';
|
|
|
|
import {select, line} from 'd3';
|
|
|
|
select, scaleLinear, scaleLog, scalePow, scaleTime,
|
|
axisLeft, axisRight, axisTop, axisBottom
|
|
|
|
export default {
|
|
name: 'MultiCountryChart',
|
|
props: {
|
|
countries: Array,
|
|
scaleType: String,
|
|
dataType: String,
|
|
width: Number,
|
|
height: Number,
|
|
},
|
|
data() {
|
|
return {
|
|
margin: {
|
|
x: 5,
|
|
y: 5,
|
|
},
|
|
svgClass: "svg" + Math.random().toString(36).substring(7),
|
|
overpoint: {
|
|
x: 0,
|
|
y: 0,
|
|
text: "",
|
|
country: ""
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
this.drawAxis()
|
|
console.log('dataType', this.dataType)
|
|
},
|
|
watch: {
|
|
scaleType(neww) {
|
|
console.log('', neww)
|
|
this.drawAxis()
|
|
},
|
|
countries() {
|
|
this.drawAxis()
|
|
},
|
|
},
|
|
computed: {
|
|
minmax() {
|
|
|
|
let max = {x: 0, y: 0}
|
|
let min = {x: new Date(), y: undefined}
|
|
|
|
this.countries.forEach(country => {
|
|
country.list.forEach((item) => {
|
|
|
|
let value = item[this.dataType]
|
|
let dayvalue = new Date(item.date)
|
|
max.x = max.x < dayvalue ? dayvalue : max.x
|
|
max.y = max.y < value ? value : max.y
|
|
|
|
min.x = min.x > dayvalue ? dayvalue : min.x
|
|
if (typeof min.y === "undefined") min.y = value
|
|
min.y = min.y > value ? value : min.y
|
|
if (min.y <= 1) min.y = 1 // for log scale
|
|
})
|
|
})
|
|
|
|
//console.log(' {min: min, max: max} ', min.y, max, this.scaleType)
|
|
return {min: min, max: max}
|
|
},
|
|
|
|
scales() {
|
|
|
|
let scales = {}
|
|
scales.x = scaleTime()
|
|
.domain([this.minmax.min.x, this.minmax.max.x])
|
|
.range([0, this.width - 2 * this.margin.x])
|
|
|
|
// !!scaleLog need to start at 1 not 0!!
|
|
scales.y = this.scaleType === 'linear' ? scaleLinear() : scaleLog()
|
|
scales.y = scales.y
|
|
.domain([this.minmax.min.y, this.minmax.max.y])
|
|
.range([this.height - 2 * this.margin.y, 1])
|
|
|
|
return scales
|
|
},
|
|
|
|
},
|
|
methods: {
|
|
overPoint(point, color) {
|
|
|
|
if (point === 'reset') {
|
|
this.overpoint = {
|
|
x: 0, y: 0, text: ""
|
|
}
|
|
return
|
|
}
|
|
|
|
this.overpoint = {
|
|
x: this.scales.x(new Date(point.date)),
|
|
y: this.scales.y(point [this.dataType]),
|
|
text: point.date.slice(5,10)+": "+point [this.dataType],
|
|
color: color,
|
|
}
|
|
},
|
|
calculatePath(data) {
|
|
|
|
//console.log('datata',data)
|
|
const path = line()
|
|
.x((d) => this.scales.x(new Date(d.date)))
|
|
.y(d => this.scales.y(d[this.dataType] === 0 ? 1 : d[this.dataType]))
|
|
|
|
return path(data)
|
|
},
|
|
drawAxis() {
|
|
|
|
let axis = select("." + this.svgClass + " .axisg")
|
|
|
|
axis.selectAll("*").remove()
|
|
|
|
axis.append("g")
|
|
.attr("class", "axis axis--y")
|
|
.attr("transform", "translate(" + 0 + ", 0)")
|
|
.call(axisRight(this.scales.y));
|
|
|
|
axis.append("g")
|
|
.attr("class", "axis axis--x")
|
|
.attr("transform", "translate( 0," + (this.height - this.margin.y/2) + ")")
|
|
.call(axisTop(this.scales.x));
|
|
|
|
},
|
|
}
|
|
}
|
|
</script>
|
|
|
|
|
|
<style lang="sass" scoped>
|
|
|
|
path
|
|
fill: none
|
|
stroke: #bf674d
|
|
stroke-width: 1px
|
|
|
|
</style>
|
|
|
|
<style>
|
|
.overpoint {
|
|
font-size: 11px;
|
|
}
|
|
</style> |