68 lines
2.0 KiB
Vue
68 lines
2.0 KiB
Vue
<template>
|
|
<div class="media">
|
|
<div class="media-left">
|
|
<slot name="value" :value="valueDisplay" :max="max">{{ format(valueDisplay) }}</slot>
|
|
</div>
|
|
<div ref="bar" class="media-content" @click.stop="onClick" @mouseleave.stop="onMouseMove"
|
|
@mousemove.stop="onMouseMove">
|
|
<div :class="progressClass" :style="progressStyle"> </div>
|
|
</div>
|
|
<div class="media-right">
|
|
<slot name="value" :value="valueDisplay" :max="max">{{ format(max) }}</slot>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
hoverValue: null,
|
|
}
|
|
},
|
|
|
|
props: {
|
|
value: Number,
|
|
max: Number,
|
|
format: { type: Function, default: x => x },
|
|
progressClass: { default: 'has-background-primary' },
|
|
vertical: { type: Boolean, default: false },
|
|
},
|
|
|
|
computed: {
|
|
valueDisplay() { return this.hoverValue === null ? this.value : this.hoverValue; },
|
|
|
|
progressStyle() {
|
|
if(!this.max)
|
|
return null;
|
|
let value = this.max ? this.valueDisplay * 100 / this.max : 0;
|
|
return this.vertical ? { height: `${value}%` } : { width: `${value}%` };
|
|
},
|
|
},
|
|
|
|
methods: {
|
|
xToValue(x) { return x * this.max / this.$refs.bar.getBoundingClientRect().width },
|
|
yToValue(y) { return y * this.max / this.$refs.bar.getBoundingClientRect().height },
|
|
|
|
valueFromEvent(event) {
|
|
let rect = event.currentTarget.getBoundingClientRect()
|
|
return this.vertical ? this.yToValue(event.clientY - rect.y)
|
|
: this.xToValue(event.clientX - rect.x);
|
|
},
|
|
|
|
onClick(event) {
|
|
this.$emit('select', this.valueFromEvent(event));
|
|
},
|
|
|
|
onMouseMove(event) {
|
|
if(event.type == 'mouseleave')
|
|
this.hoverValue = null;
|
|
else {
|
|
this.hoverValue = this.valueFromEvent(event);
|
|
}
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|