blob: fc549afd418c6cfc77cd065957efc40756497528 [file] [log] [blame]
<template>
<div class="w-full h-full">
<div class="grid grid-cols-12 h-full text-sm">
<el-card class="box-card col-span-3 scroll-card">
<h1 slot="header" class="clearfix text-xl">
{{$t('toolName')}}
<span id="github-button">
<a class="github-button" href="https://github.com/apache/echarts-bar-racing" data-size="large" data-show-count="true" aria-label="Star apache/echarts-bar-racing on GitHub">Star</a>
</span>
</h1>
<div id="el-config" class="align-middle">
<el-form ref="form" :disabled="isExportingVideo">
<h2>
{{$t('chartConfigs')}}
</h2>
<el-row>
<el-select v-model="selectedDemo"
@change="onTitleChanged($event)"
>
<el-option
value="complicated"
:label="titleComplicated"
>
</el-option>
<el-option
value="simple"
:label="titleSimple"
>
</el-option>
<el-option
value="none"
:label="titleNone"
>
</el-option>
</el-select>
</el-row>
<el-row>
<el-col :span="12">
{{$t('chartTitle')}}
</el-col>
<el-col :span="12">
<el-input
id="input-title"
size="medium"
class="col-span-1"
v-model="title"
@change="runChart"
>
</el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
{{$t('maxDataCount')}}
</el-col>
<el-col :span="12">
<el-input
id="input-max"
type="number"
value=""
size="medium"
class="col-span-2"
:placeholder="$t('maxDataPlaceholder')"
v-model.number="maxDataCnt"
@change="runChart"
>
</el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
{{$t('animationDuration')}}
</el-col>
<el-col :span="12">
<el-input
id="input-animation-duration"
type="number"
size="medium"
class="col-span-2"
v-model="animationDuration"
@change="runChart"
>
</el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
{{$t('reorderDuration')}}
</el-col>
<el-col :span="12">
<el-input
id="input-sort-duration"
type="number"
value="500"
size="medium"
class="col-span-2"
v-model="sortDuration"
@change="runChart"
>
</el-input>
</el-col>
</el-row>
<el-row>
<el-button @click="download" type="primary">
<i class="el-icon-download"></i>
{{$t('download')}}
</el-button>
</el-row>
<el-divider></el-divider>
<h2>{{$t('videoConfig')}}</h2>
<el-row>
<el-col :span="12">
{{$t('videoWidth')}}
</el-col>
<el-col :span="12">
<el-input
type="number"
size="medium"
class="col-span-2"
v-model="width"
>
</el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
{{$t('videoHeight')}}
</el-col>
<el-col :span="12">
<el-input
type="number"
size="medium"
class="col-span-2"
v-model="height"
>
</el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
{{$t('videoFps')}}
</el-col>
<el-col :span="12">
<el-input
type="number"
size="medium"
class="col-span-2"
v-model="fps"
>
</el-input>
</el-col>
</el-row>
<el-row>
<el-button @click="downloadVideo" v-if="isChrome">
<i class="el-icon-video-camera"></i>
{{$t('generateVideo')}}
</el-button>
<el-label class="mt-4 text-red-600" v-if="!isChrome">
{{$t('videoSupported')}}
</el-label>
</el-row>
</el-form>
</div>
</el-card>
<el-card
v-if="!isExportingVideo"
class="box-card col-span-4 relative"
body-style="height: 100%"
>
<BTable
ref="btable"
:demoData="demoData"
@after-change="tableAfterChange"
/>
</el-card>
<el-card
class="box-card relative"
:class="isExportingVideo ? 'col-span-9' : 'col-span-5'"
body-style="height: 100%"
>
<BChart
ref="bchart"
:title="title"
:chartData="chartData"
:maxDataCnt="maxDataCnt"
:animationDuration="animationDuration"
:sortDuration="sortDuration"
@downloadCancelled="downloadCancelled"
/>
</el-card>
</div>
</div>
</template>
<script lang="ts">
import {defineComponent} from 'vue';
import BTable, {ChartData} from './BTable.vue';
import BChart from './BChart.vue';
import template from '../helper/template';
import fruit from '../data/fruit';
import expectancy from '../data/expectancy';
export default defineComponent({
name: 'BBody',
data() {
const i18n = this.$i18n as any;
return {
isChrome: /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor),
selectedDemo: 'complicated',
demoData: expectancy,
title: i18n.t('titleComplicated'),
titleComplicated: i18n.t('titleComplicated'),
titleSimple: i18n.t('titleSimple'),
titleNone: i18n.t('titleNone'),
maxDataCnt: 10,
chartData: null,
animationDuration: 3000,
sortDuration: 300,
width: 1280,
height: 720,
fps: 30,
videoPercentage: 40,
isExportingVideo: false
}
},
components: {
BTable,
BChart
},
mounted: () => {
},
methods: {
tableAfterChange(data: ChartData) {
this.chartData = data;
},
runChart() {
(this.$refs.bchart as any).run();
},
setData(name: 'fruit' | 'expectancy') {
if (name === 'fruit') {
this.demoData = fruit;
this.title = this.titleComplicated;
} else {
this.demoData = expectancy;
this.title = this.titleSimple;
}
setTimeout(() => {
this.$refs.btable.reset();
this.$refs.bchart.run();
});
},
onTitleChanged(demoName) {
if (demoName === 'simple') {
this.demoData = fruit;
this.title = this.titleSimple;
this.maxDataCnt = null;
}
else if (demoName === 'complicated') {
this.demoData = expectancy;
this.title = this.titleComplicated;
this.maxDataCnt = 10;
}
else {
this.demoData = [[], []];
this.title = this.titleNone;
this.maxDataCnt = null;
}
setTimeout(() => {
this.$refs.btable.reset();
this.$refs.chart
});
},
download() {
let html = template;
const map = {
animationDuration: this.animationDuration,
maxDataCnt: this.maxDataCnt,
title: this.title,
data: (this.$refs.btable as any).getChartData(),
sortDuration: this.sortDuration
};
for (let attr in map) {
const value = (map as any)[attr];
html = html.replace(`{{${attr}}}`, JSON.stringify(value));
}
const element = document.createElement('a');
element.setAttribute('href', 'data:text/html;charset=utf-8,' + encodeURIComponent(html));
element.setAttribute('download', 'echarts-bar-racing.html');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
},
async downloadVideo() {
if (!this.width || !this.height) {
this.$notify.error({
title: this.$i18n.t('videSizeError'),
message: this.$i18n.t('videSizeErrorHint'),
duration: 0,
position: 'bottom-left'
});
return;
}
this.isExportingVideo = true;
const isSuccess = await (this.$refs.bchart as any).captureVideo(this.width, this.height, this.fps);
this.isExportingVideo = false;
if (isSuccess) {
this.$notify({
title: this.$i18n.t('videoSuccess'),
type: 'success',
duration: 3000,
position: 'bottom-left'
});
}
else {
this.$notify.error({
title: this.$i18n.t('videoFail'),
message: this.$i18n.t('videoFailHint'),
duration: 0,
position: 'bottom-left'
});
}
},
downloadCancelled() {
this.isExportingVideo = false;
}
}
})
</script>
<style scoped>
#github-button {
float: right;
}
.scroll-card {
overflow-y: auto;
}
.el-col-12 {
place-self: center;
}
h1 {
margin-bottom: 15px;
font-weight: bold;
font-size: 1.75rem;
}
h2 {
margin-bottom: 15px;
font-size: 1.4rem;
font-weight: bold;
}
.hint {
color: #999;
font-size: 12px;
}
.el-button i {
display: inline-block;
margin-right: 2px;
}
@layer utilities {
.el-row {
@apply my-3;
label {
@apply py-1;
}
}
.box-card {
@apply m-1;
}
}
</style>