You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by ov...@apache.org on 2021/09/09 06:20:13 UTC

[echarts-bar-racing] branch master updated (f1955e4 -> 6c5567d)

This is an automated email from the ASF dual-hosted git repository.

ovilia pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/echarts-bar-racing.git.


    from f1955e4  basic download video
     new 984e2f7  feat: record video basic logic done
     new 6c5567d  feat: export video done

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/components/BBody.vue  | 258 +++++++++++++++++++++++++++++++---------------
 src/components/BChart.vue |  69 +++++++++----
 src/components/BTable.vue |   2 +-
 src/helper/template.ts    |   9 +-
 src/i18n/en-US.ts         |   3 +-
 src/i18n/zh-CN.ts         |   3 +-
 6 files changed, 238 insertions(+), 106 deletions(-)

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org


[echarts-bar-racing] 01/02: feat: record video basic logic done

Posted by ov...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ovilia pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/echarts-bar-racing.git

commit 984e2f79dd18798a90496eb300c91f0abe415423
Author: Ovilia <zw...@gmail.com>
AuthorDate: Thu Sep 9 11:18:05 2021 +0800

    feat: record video basic logic done
---
 src/components/BBody.vue  | 19 ++++++++-----------
 src/components/BChart.vue | 26 +++++++++++++++++++++-----
 2 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/src/components/BBody.vue b/src/components/BBody.vue
index b7a363d..1ad168f 100644
--- a/src/components/BBody.vue
+++ b/src/components/BBody.vue
@@ -1,5 +1,8 @@
 <template>
-    <div class="w-full h-full">
+    <div class="w-full h-full"
+        v-loading="isExportingVideo"
+        element-loading-text="视频生成中"
+    >
         <div class="grid grid-cols-12 h-full text-sm">
             <el-card class="box-card col-span-3">
                 <h1 slot="header" class="clearfix text-xl">
@@ -68,15 +71,6 @@
                             <el-button @click="download" type="primary">下载代码</el-button>
                             <el-button @click="downloadVideo">生成视频</el-button>
                         </el-form-item>
-
-                        <div class="grid grid-cols-3 form-row">
-                            <label class="col-span-1">视频生成中</label>
-                            <el-progress class="col-span-2"
-                                :text-inside="true"
-                                :stroke-width="20"
-                                :percentage="videoPercentage">
-                            </el-progress>
-                        </div>
                     </el-form>
                 </div>
             </el-card>
@@ -122,7 +116,8 @@ export default defineComponent({
             animationDuration: 3000,
             width: 1280,
             height: 720,
-            videoPercentage: 40
+            videoPercentage: 40,
+            isExportingVideo: false
         }
     },
     components: {
@@ -163,7 +158,9 @@ export default defineComponent({
         },
 
         async downloadVideo() {
+            // this.isExportingVideo = true;
             const isSuccess = await (this.$refs.bchart as any).captureVideo(this.width, this.height);
+            // this.isExportingVideo = false;
             if (!isSuccess) {
                 // this.$notify.error({
                 //     title: '导出失败!',
diff --git a/src/components/BChart.vue b/src/components/BChart.vue
index f011be7..c0f83a2 100644
--- a/src/components/BChart.vue
+++ b/src/components/BChart.vue
@@ -37,6 +37,7 @@ const colorAll = [
 ];
 const headerLength = 2;
 let chart: echarts.ECharts;
+let time: number;
 
 export default defineComponent({
     name: 'BChart',
@@ -62,6 +63,7 @@ export default defineComponent({
     methods: {
         run() {
             this.doResetChart();
+            time = Date.now();
             this.doRun();
         },
 
@@ -87,11 +89,25 @@ export default defineComponent({
                     this.doResetChart(width, height);
                     const canvas = chart.getDom().children[0].children[0] as HTMLCanvasElement;
                     const recorder = canvasRecord(canvas);
+                    time = Date.now();
+
+                    recorder.start();
+
+                    this.doRun(() => {
+                        let hasError = false;
+                        try {
+                            recorder.stop();
+                        }
+                        catch (e) {
+                            console.error(e);
+                            hasError = true;
+                        }
 
-                    this.doRun(5000, () => {
-                        recorder.stop();
                         this.isHidden = false;
-                        resolve(true);
+                        setTimeout(() => {
+                            this.run();
+                        });
+                        resolve(hasError);
                     });
                 }
                 catch (e) {
@@ -175,7 +191,7 @@ export default defineComponent({
             chart.setOption(option as echarts.EChartsOption, true);
         },
 
-        doRun(timePadding?: number, onCompleted?: Function) {
+        doRun(onCompleted?: Function) {
             const dataCnt = this.chartData.length - headerLength - 1;
             const that = this;
             for (let i = 0; i < dataCnt; ++i) {
@@ -198,7 +214,7 @@ export default defineComponent({
                         });
                         that.removeTimeoutHandlers(timeout);
                         if (i === dataCnt - 1 && typeof onCompleted === 'function') {
-                            setTimeout(onCompleted, timePadding);
+                            setTimeout(onCompleted, that.animationDuration);
                         }
                     };
                     timeout = window.setTimeout(timeoutCb, i * that.animationDuration);

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org


[echarts-bar-racing] 02/02: feat: export video done

Posted by ov...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ovilia pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/echarts-bar-racing.git

commit 6c5567d2539dd51a07520cf07603768c5548ca48
Author: Ovilia <zw...@gmail.com>
AuthorDate: Thu Sep 9 14:20:01 2021 +0800

    feat: export video done
---
 src/components/BBody.vue  | 253 +++++++++++++++++++++++++++++++---------------
 src/components/BChart.vue |  45 ++++++---
 src/components/BTable.vue |   2 +-
 src/helper/template.ts    |   9 +-
 src/i18n/en-US.ts         |   3 +-
 src/i18n/zh-CN.ts         |   3 +-
 6 files changed, 217 insertions(+), 98 deletions(-)

diff --git a/src/components/BBody.vue b/src/components/BBody.vue
index 1ad168f..d0d1638 100644
--- a/src/components/BBody.vue
+++ b/src/components/BBody.vue
@@ -1,80 +1,126 @@
 <template>
-    <div class="w-full h-full"
-        v-loading="isExportingVideo"
-        element-loading-text="视频生成中"
-    >
+    <div class="w-full h-full">
         <div class="grid grid-cols-12 h-full text-sm">
-            <el-card class="box-card col-span-3">
+            <el-card class="box-card col-span-3 scroll-card">
                 <h1 slot="header" class="clearfix text-xl">
                     {{$t('toolName')}}
                 </h1>
                 <div id="el-config" class="align-middle">
-                    <el-form ref="form">
-                        <div class="grid grid-cols-3 form-row">
-                            <label class="col-span-1">{{$t('chartTitle')}}</label>
-                            <el-input
-                                id="input-title"
-                                size="medium"
-                                class="col-span-2"
-                                v-model="title"
-                                @change="runChart"
-                            >
-                            </el-input>
-                        </div>
-                        <div class="grid grid-cols-3 form-row">
-                            <label class="col-span-1">显示排名上限</label>
-                            <el-input
-                                id="input-max"
-                                type="number"
-                                value=""
-                                size="medium"
-                                class="col-span-2"
-                                v-model="maxDataCnt"
-                                @change="runChart"
-                            >
-                            </el-input>
-                        </div>
-                        <div class="grid grid-cols-3 form-row">
-                            <label class="col-span-1">每行动画时长(毫秒)</label>
-                            <el-input
-                                id="input-animation-duration"
-                                type="number"
-                                value="5000"
-                                size="medium"
-                                class="col-span-2"
-                                v-model="animationDuration"
-                                @change="runChart"
-                            >
-                            </el-input>
-                        </div>
-                        <div class="grid grid-cols-3 form-row">
-                            <label class="col-span-1">视频宽度</label>
-                            <el-input
-                                type="number"
-                                size="medium"
-                                class="col-span-2"
-                                v-model="width"
-                            >
-                            </el-input>
-                        </div>
-                        <div class="grid grid-cols-3 form-row">
-                            <label class="col-span-1">视频高度</label>
-                            <el-input
-                                type="number"
-                                size="medium"
-                                class="col-span-2"
-                                v-model="height"
-                            >
-                            </el-input>
-                        </div>
-                        <el-form-item>
-                            <el-button @click="download" type="primary">下载代码</el-button>
-                            <el-button @click="downloadVideo">生成视频</el-button>
-                        </el-form-item>
+                    <el-form ref="form" :disabled="isExportingVideo">
+                        <h2>图表设置</h2>
+                        <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">
+                                显示排名上限
+                            </el-col>
+                            <el-col :span="12">
+                                <el-input
+                                    id="input-max"
+                                    type="number"
+                                    value=""
+                                    size="medium"
+                                    class="col-span-2"
+                                    placeholder="为空则显示所有"
+                                    v-model="maxDataCnt"
+                                    @change="runChart"
+                                >
+                                </el-input>
+                            </el-col>
+                        </el-row>
+                        <el-row>
+                            <el-col :span="12">
+                                每行动画时长<span class="hint">(毫秒)</span>
+                            </el-col>
+                            <el-col :span="12">
+                                <el-input
+                                    id="input-animation-duration"
+                                    type="number"
+                                    value="5000"
+                                    size="medium"
+                                    class="col-span-2"
+                                    v-model="animationDuration"
+                                    @change="runChart"
+                                >
+                                </el-input>
+                            </el-col>
+                        </el-row>
+                        <el-row>
+                            <el-button @click="download" type="primary">
+                                <i class="el-icon-download"></i>
+                                下载代码
+                            </el-button>
+                        </el-row>
+
+                        <el-divider></el-divider>
+
+                        <h2>视频设置</h2>
+                        <el-row>
+                            <el-col :span="12">
+                                视频宽度
+                            </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">
+                                视频高度
+                            </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">
+                                视频帧率<span class="hint">(FPS)</span>
+                            </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">
+                                <i class="el-icon-video-camera"></i>
+                                生成视频
+                            </el-button>
+                        </el-row>
                     </el-form>
                 </div>
             </el-card>
             <el-card
+                v-if="!isExportingVideo"
                 class="box-card col-span-4 relative"
                 body-style="height: 100%"
             >
@@ -84,7 +130,8 @@
                 />
             </el-card>
             <el-card
-                class="box-card col-span-5 relative"
+                class="box-card relative"
+                :class="isExportingVideo ? 'col-span-9' : 'col-span-5'"
                 body-style="height: 100%"
             >
                 <BChart
@@ -116,6 +163,7 @@ export default defineComponent({
             animationDuration: 3000,
             width: 1280,
             height: 720,
+            fps: 30,
             videoPercentage: 40,
             isExportingVideo: false
         }
@@ -158,16 +206,34 @@ export default defineComponent({
         },
 
         async downloadVideo() {
-            // this.isExportingVideo = true;
-            const isSuccess = await (this.$refs.bchart as any).captureVideo(this.width, this.height);
-            // this.isExportingVideo = false;
-            if (!isSuccess) {
-                // this.$notify.error({
-                //     title: '导出失败!',
-                //     message: '建议使用最新版 Chrome 或 Firefox',
-                //     duration: 0,
-                //     position: 'bottom-left'
-                // });
+            if (!this.width || !this.height) {
+                this.$notify.error({
+                    title: '视频高度宽度错误!',
+                    message: '高度宽度不能为 0',
+                    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: '导出成功!',
+                    type: 'success',
+                    duration: 3000,
+                    position: 'bottom-left'
+                });
+            }
+            else {
+                this.$notify.error({
+                    title: '导出失败!',
+                    message: '建议使用最新版 Chrome 或 Firefox',
+                    duration: 0,
+                    position: 'bottom-left'
+                });
             }
         }
     }
@@ -175,8 +241,37 @@ export default defineComponent({
 </script>
 
 <style scoped>
+.scroll-card {
+    overflow-y: auto;
+}
+
+.el-col-12 {
+    place-self: center;
+}
+
+h1 {
+    margin-bottom: 15px;
+    font-weight: bold;
+}
+
+h2 {
+    margin-bottom: 15px;
+    font-size: 16px;
+    font-weight: bold;
+}
+
+.hint {
+    color: #999;
+    font-size: 12px;
+}
+
+.el-button i {
+    display: inline-block;
+    margin-right: 2px;
+}
+
 @layer utilities {
-    .form-row {
+    .el-row {
         @apply my-3;
 
         label {
diff --git a/src/components/BChart.vue b/src/components/BChart.vue
index c0f83a2..c0ab889 100644
--- a/src/components/BChart.vue
+++ b/src/components/BChart.vue
@@ -1,21 +1,21 @@
 <template>
     <div>
-        <div slot="header" class="clearfix text-base">
+        <div slot="header" class="clearfix text-base" v-if="!isExportingVideo">
             {{$t('preview')}}
             <a href="javascript:;" @click="run()">
                 <i class="el-icon-refresh"></i>
             </a>
         </div>
+        <div slot="header" class="clearfix text-base" v-if="isExportingVideo">
+            <i class="el-icon-loading"></i>
+            {{$t('exporting')}}
+        </div>
         <div
             id="bar-race-preview"
             ref="chart"
             class="absolute bottom-4 top-14 left-5 right-5 border"
-            :class="isHidden ? 'hidden' : ''"
         >
         </div>
-        <div id="chart-hint" v-if="isHidden">
-            视频生成中无法预览
-        </div>
     </div>
 </template>
 
@@ -50,7 +50,7 @@ export default defineComponent({
     data() {
         return {
             timeoutHandlers: [],
-            isHidden: false
+            isExportingVideo: false
         };
     },
     watch: {
@@ -82,13 +82,28 @@ export default defineComponent({
             }
         },
 
-        captureVideo(width?: number, height?: number): Promise<boolean> {
+        captureVideo(width: number, height: number, fps: number): Promise<boolean> {
             return new Promise(resolve => {
                 try {
-                    this.isHidden = true;
+                    this.isExportingVideo = true;
                     this.doResetChart(width, height);
-                    const canvas = chart.getDom().children[0].children[0] as HTMLCanvasElement;
-                    const recorder = canvasRecord(canvas);
+                    const container = chart.getDom();
+                    const canvas = container.children[0].children[0] as HTMLCanvasElement;
+                    if (container.clientHeight) {
+                        if (container.clientWidth / container.clientHeight > width / height) {
+                            canvas.style.height = container.clientHeight + 'px';
+                            canvas.style.width = container.clientHeight / height * width + 'px';
+                        }
+                        else {
+                            canvas.style.width = container.clientWidth + 'px';
+                            canvas.style.height = container.clientWidth / width * height + 'px';
+                        }
+                    }
+
+                    const recorder = canvasRecord(canvas, {
+                        frameRate: fps || 30,
+                        filename: this.title || this.$t('toolName')
+                    });
                     time = Date.now();
 
                     recorder.start();
@@ -103,16 +118,16 @@ export default defineComponent({
                             hasError = true;
                         }
 
-                        this.isHidden = false;
+                        this.isExportingVideo = false;
                         setTimeout(() => {
                             this.run();
+                            resolve(!hasError);
                         });
-                        resolve(hasError);
                     });
                 }
                 catch (e) {
                     console.error(e);
-                    this.isHidden = false;
+                    this.isExportingVideo = false;
                     resolve(false);
                 }
             });
@@ -167,7 +182,9 @@ export default defineComponent({
                 }],
                 grid: {
                     right: 60,
-                    bottom: 30
+                    bottom: 30,
+                    left: 20,
+                    containLabel: true
                 },
                 title: [{
                     text: (this.chartData as any)[headerLength][0],
diff --git a/src/components/BTable.vue b/src/components/BTable.vue
index 81a0c33..c3b883a 100644
--- a/src/components/BTable.vue
+++ b/src/components/BTable.vue
@@ -39,7 +39,7 @@ export default defineComponent({
     data() {
         return {
             tableData: [
-                ['', 'blueberry', 'banana', 'kiwi', 'watermelon']
+                ['', 'blueberry', 'kiwi', 'banana', 'watermelon']
                     // @ts-ignore:
                     .map(name => name ? this.$i18n.t(name) : ''),
                 // @ts-ignore:
diff --git a/src/helper/template.ts b/src/helper/template.ts
index 6f89e3c..8f49db7 100644
--- a/src/helper/template.ts
+++ b/src/helper/template.ts
@@ -82,10 +82,12 @@ export default `
                 }],
                 grid: {
                     right: 60,
-                    bottom: 30
+                    bottom: 30,
+                    left: 20,
+                    containLabel: true
                 },
                 title: [{
-                    text: 'aaa',
+                    text: data[headerLength][0],
                     right: 20,
                     bottom: 15,
                     textStyle: {
@@ -118,6 +120,9 @@ export default `
                                 label: {
                                     valueAnimation: true
                                 }
+                            }],
+                            title: [{
+                                text: data[headerLength + i + 1][0]
                             }]
                         });
                         removeTimeoutHandlers(timeout);
diff --git a/src/i18n/en-US.ts b/src/i18n/en-US.ts
index 2e7deaf..fda190d 100644
--- a/src/i18n/en-US.ts
+++ b/src/i18n/en-US.ts
@@ -11,5 +11,6 @@ export default {
     banana: 'Banana',
     kiwi: 'Kiwi',
     watermelon: 'Watermelon',
-    preview: 'Preview'
+    preview: 'Preview',
+    exporting: 'The video is under exporting'
 };
diff --git a/src/i18n/zh-CN.ts b/src/i18n/zh-CN.ts
index 8837bda..af328e7 100644
--- a/src/i18n/zh-CN.ts
+++ b/src/i18n/zh-CN.ts
@@ -15,7 +15,8 @@ const langCn: DEFAULT_LANG_TYPE = {
     banana: '香蕉',
     kiwi: '猕猴桃',
     watermelon: '西瓜',
-    preview: '预览'
+    preview: '预览',
+    exporting: '视频正在导出中'
 };
 
 export default langCn;
\ No newline at end of file

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org