covcharts/src/components/d3/MultiCountryChart.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>