feat: Add count-to demo

feat: Add useWatermark hook and add useWatermark demo
This commit is contained in:
陈凯龙 2022-01-26 14:08:37 +08:00
parent e4b7a76912
commit d3fbd3a06c
10 changed files with 432 additions and 7 deletions

View File

@ -8,9 +8,7 @@ export const usePageLoading = () => {
}
const loadDone = () => {
setTimeout(() => {
appStore.setPageLoading(false)
}, 1000)
appStore.setPageLoading(false)
}
return {

View File

@ -0,0 +1,55 @@
const domSymbol = Symbol('watermark-dom')
export function useWatermark(appendEl: HTMLElement | null = document.body) {
let func: Fn = () => {}
const id = domSymbol.toString()
const clear = () => {
const domId = document.getElementById(id)
if (domId) {
const el = appendEl
el && el.removeChild(domId)
}
window.removeEventListener('resize', func)
}
const createWatermark = (str: string) => {
clear()
const can = document.createElement('canvas')
can.width = 300
can.height = 240
const cans = can.getContext('2d')
if (cans) {
cans.rotate((-20 * Math.PI) / 120)
cans.font = '15px Vedana'
cans.fillStyle = 'rgba(0, 0, 0, 0.15)'
cans.textAlign = 'left'
cans.textBaseline = 'middle'
cans.fillText(str, can.width / 20, can.height)
}
const div = document.createElement('div')
div.id = id
div.style.pointerEvents = 'none'
div.style.top = '0px'
div.style.left = '0px'
div.style.position = 'absolute'
div.style.zIndex = '100000000'
div.style.width = document.documentElement.clientWidth + 'px'
div.style.height = document.documentElement.clientHeight + 'px'
div.style.background = 'url(' + can.toDataURL('image/png') + ') left top repeat'
const el = appendEl
el && el.appendChild(div)
return id
}
function setWatermark(str: string) {
createWatermark(str)
func = () => {
createWatermark(str)
}
window.addEventListener('resize', func)
}
return { setWatermark, clear }
}

View File

@ -87,7 +87,10 @@ export default {
workplace: 'Workplace',
guide: 'Guide',
component: 'Component',
icon: 'Icon'
icon: 'Icon',
echart: 'Echart',
countTo: 'Count to',
watermark: 'Watermark'
},
analysis: {
newUser: 'New user',
@ -203,5 +206,30 @@ export default {
recommendeDes:
'Iconify component basically contains all icons. You can query any icon you want. And packaging will only package the icons used.',
accessAddress: 'Access address'
},
echartDemo: {
echart: 'Echart',
echartDes:
'Based on the secondary packaging components of eckarts, the width is adaptive. The corresponding chart can be displayed by passing in the options and height attributes.'
},
countToDemo: {
countTo: 'CountTo',
countToDes:
'The transformation is based on vue-count-to and supports all vue-count-to parameters.',
suffix: 'Suffix',
prefix: 'Prefix',
separator: 'Separator',
duration: 'Duration',
endVal: 'End val',
startVal: 'Start val',
start: 'Start',
pause: 'Pause',
resume: 'Resume'
},
watermarkDemo: {
watermark: 'Watermark',
createdWatermark: 'Created watermark',
clearWatermark: 'Clear watermark',
resetWatermark: 'Reset watermark'
}
}

View File

@ -87,7 +87,10 @@ export default {
workplace: '工作台',
guide: '引导',
component: '组件',
icon: '图标'
icon: '图标',
echart: '图表',
countTo: '数字动画',
watermark: '水印'
},
analysis: {
newUser: '新增用户',
@ -203,5 +206,29 @@ export default {
recommendeDes:
'Iconify组件基本包含所有的图标你可以查询到你想要的任何图标。并且打包只会打包所用到的图标。',
accessAddress: '访问地址'
},
echartDemo: {
echart: '图表',
echartDes:
'基于 echarts 二次封装组件,自适应宽度,只需传入 options 与 height 属性即可展示对应的图表。'
},
countToDemo: {
countTo: '数字动画',
countToDes: '基于 vue-count-to 进行改造,支持所有 vue-count-to 参数。',
suffix: '后缀',
prefix: '前缀',
separator: '分割符号',
duration: '持续时间',
endVal: '结束值',
startVal: '开始值',
start: '开始',
pause: '暂停',
resume: '继续'
},
watermarkDemo: {
watermark: '水印',
createdWatermark: '创建水印',
clearWatermark: '清除水印',
resetWatermark: '重置水印'
}
}

View File

@ -103,6 +103,30 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
meta: {
title: t('router.icon')
}
},
{
path: 'echart',
component: () => import('@/views/Components/Echart.vue'),
name: 'Echart',
meta: {
title: t('router.echart')
}
},
{
path: 'count-to',
component: () => import('@/views/Components/CountTo.vue'),
name: 'CountTo',
meta: {
title: t('router.countTo')
}
},
{
path: 'watermark',
component: () => import('@/views/Components/Watermark.vue'),
name: 'Watermark',
meta: {
title: t('router.watermark')
}
}
]
},

View File

@ -0,0 +1,100 @@
<script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
import { useI18n } from '@/hooks/web/useI18n'
import { CountTo } from '@/components/CountTo'
import { ElRow, ElCol, ElInputNumber, ElInput, ElButton } from 'element-plus'
import { ref, unref } from 'vue'
const { t } = useI18n()
const countRef = ref<ComponentRef<typeof CountTo>>()
const startVal = ref(0)
const endVal = ref(1314512)
const duration = ref(3000)
const decimals = ref(0)
const separator = ref(',')
const prefix = ref('¥ ')
const suffix = ref(' rmb')
const autoplay = ref(false)
const start = () => {
unref(countRef)?.start()
}
const pauseResume = () => {
unref(countRef)?.pauseResume()
}
</script>
<template>
<ContentWrap :title="t('countToDemo.countTo')" :message="t('countToDemo.countToDes')">
<div class="text-center mb-40px">
<CountTo
ref="countRef"
:start-val="startVal"
:end-val="endVal"
:duration="duration"
:decimals="decimals"
:separator="separator"
:prefix="prefix"
:suffix="suffix"
:autoplay="autoplay"
class="text-30px font-bold text-[var(--el-color-primary)]"
/>
</div>
<ElRow :gutter="20" justify="space-between">
<ElCol :xl="8" :lg="8" :md="12" :sm="24" :xs="24">
<div class="flex mb-20px items-center">
<span class="min-w-90px text-right">{{ t('countToDemo.startVal') }}</span>
<ElInputNumber v-model="startVal" :min="0" />
</div>
</ElCol>
<ElCol :xl="8" :lg="8" :md="12" :sm="24" :xs="24">
<div class="flex mb-20px items-center">
<span class="min-w-90px text-right">{{ t('countToDemo.endVal') }}</span>
<ElInputNumber v-model="endVal" :min="1" />
</div>
</ElCol>
<ElCol :xl="8" :lg="8" :md="12" :sm="24" :xs="24">
<div class="flex mb-20px items-center">
<span class="min-w-90px text-right">{{ t('countToDemo.duration') }}</span>
<ElInputNumber v-model="duration" :min="1000" />
</div>
</ElCol>
<ElCol :xl="8" :lg="8" :md="12" :sm="24" :xs="24">
<div class="flex mb-20px items-center">
<span class="min-w-90px text-right">{{ t('countToDemo.separator') }}</span>
<ElInput v-model="separator" />
</div>
</ElCol>
<ElCol :xl="8" :lg="8" :md="12" :sm="24" :xs="24">
<div class="flex mb-20px items-center">
<span class="min-w-90px text-right">{{ t('countToDemo.prefix') }}</span>
<ElInput v-model="prefix" />
</div>
</ElCol>
<ElCol :xl="8" :lg="8" :md="12" :sm="24" :xs="24">
<div class="flex mb-20px items-center">
<span class="min-w-90px text-right">{{ t('countToDemo.suffix') }}</span>
<ElInput v-model="suffix" />
</div>
</ElCol>
<ElCol :span="24">
<div class="text-center">
<ElButton type="primary" @click="start">{{ t('countToDemo.start') }}</ElButton>
<ElButton @click="pauseResume">
{{ t('countToDemo.pause') }}/{{ t('countToDemo.resume') }}
</ElButton>
</div>
</ElCol>
</ElRow>
</ContentWrap>
</template>

View File

@ -0,0 +1,36 @@
<script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
import { useI18n } from '@/hooks/web/useI18n'
import { pieOptions, barOptions, lineOptions, wordOptions } from '@/views/Dashboard/echarts-data'
import { Echart } from '@/components/Echart'
import { ElRow, ElCol, ElCard } from 'element-plus'
const { t } = useI18n()
</script>
<template>
<ContentWrap :title="t('echartDemo.echart')" :message="t('echartDemo.echartDes')">
<ElRow :gutter="20" justify="space-between">
<ElCol :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
<ElCard shadow="hover" class="mb-20px">
<Echart :options="pieOptions" :height="300" />
</ElCard>
</ElCol>
<ElCol :xl="14" :lg="14" :md="24" :sm="24" :xs="24">
<ElCard shadow="hover" class="mb-20px">
<Echart :options="barOptions" :height="300" />
</ElCard>
</ElCol>
<ElCol :span="24">
<ElCard shadow="hover" class="mb-20px">
<Echart :options="lineOptions" :height="350" />
</ElCard>
</ElCol>
<ElCol :span="24">
<ElCard shadow="hover" class="mb-20px">
<Echart :options="wordOptions" :height="300" />
</ElCard>
</ElCol>
</ElRow>
</ContentWrap>
</template>

View File

@ -0,0 +1,32 @@
<script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
import { useI18n } from '@/hooks/web/useI18n'
import { ElButton } from 'element-plus'
import { useWatermark } from '@/hooks/web/useWatermark'
import { computed, onBeforeUnmount } from 'vue'
import { useAppStore } from '@/store/modules/app'
const appStore = useAppStore()
const title = computed(() => appStore.getTitle)
const { setWatermark, clear } = useWatermark()
const { t } = useI18n()
onBeforeUnmount(() => {
clear()
})
</script>
<template>
<ContentWrap :title="t('watermarkDemo.watermark')">
<ElButton type="primary" @click="setWatermark(title)">
{{ t('watermarkDemo.createdWatermark') }}
</ElButton>
<ElButton type="danger" @click="clear">{{ t('watermarkDemo.clearWatermark') }}</ElButton>
<ElButton type="warning" @click="setWatermark(`${title}-new`)">
{{ t('watermarkDemo.resetWatermark') }}
</ElButton>
</ContentWrap>
</template>

View File

@ -17,7 +17,7 @@ const { t } = useI18n()
const loading = ref(true)
const pieOptionsData = reactive<EChartsOption>(pieOptions)
const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
//
const getUserAccessSource = async () => {
@ -100,7 +100,7 @@ getAllApi()
<ElCol :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
<ElCard shadow="hover" class="mb-20px">
<ElSkeleton :loading="loading" animated>
<Echart :options="pieOptions" :height="300" />
<Echart :options="pieOptionsData" :height="300" />
</ElSkeleton>
</ElCard>
</ElCol>

View File

@ -1,4 +1,5 @@
import { EChartsOption } from 'echarts'
import { EChartsOption as EChartsWordOption } from 'echarts-wordcloud'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
@ -183,3 +184,127 @@ export const radarOption: EChartsOption = {
}
]
}
export const wordOptions: EChartsWordOption = {
series: [
{
type: 'wordCloud',
gridSize: 2,
sizeRange: [12, 50],
rotationRange: [-90, 90],
shape: 'pentagon',
width: 600,
height: 400,
drawOutOfBound: true,
textStyle: {
color: function () {
return (
'rgb(' +
[
Math.round(Math.random() * 160),
Math.round(Math.random() * 160),
Math.round(Math.random() * 160)
].join(',') +
')'
)
}
},
emphasis: {
textStyle: {
shadowBlur: 10,
shadowColor: '#333'
}
},
data: [
{
name: 'Sam S Club',
value: 10000,
textStyle: {
color: 'black'
},
emphasis: {
textStyle: {
color: 'red'
}
}
},
{
name: 'Macys',
value: 6181
},
{
name: 'Amy Schumer',
value: 4386
},
{
name: 'Jurassic World',
value: 4055
},
{
name: 'Charter Communications',
value: 2467
},
{
name: 'Chick Fil A',
value: 2244
},
{
name: 'Planet Fitness',
value: 1898
},
{
name: 'Pitch Perfect',
value: 1484
},
{
name: 'Express',
value: 1112
},
{
name: 'Home',
value: 965
},
{
name: 'Johnny Depp',
value: 847
},
{
name: 'Lena Dunham',
value: 582
},
{
name: 'Lewis Hamilton',
value: 555
},
{
name: 'KXAN',
value: 550
},
{
name: 'Mary Ellen Mark',
value: 462
},
{
name: 'Farrah Abraham',
value: 366
},
{
name: 'Rita Ora',
value: 360
},
{
name: 'Serena Williams',
value: 282
},
{
name: 'NCAA baseball tournament',
value: 273
},
{
name: 'Point Break',
value: 265
}
]
}
]
}