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 = () => { const loadDone = () => {
setTimeout(() => { appStore.setPageLoading(false)
appStore.setPageLoading(false)
}, 1000)
} }
return { 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', workplace: 'Workplace',
guide: 'Guide', guide: 'Guide',
component: 'Component', component: 'Component',
icon: 'Icon' icon: 'Icon',
echart: 'Echart',
countTo: 'Count to',
watermark: 'Watermark'
}, },
analysis: { analysis: {
newUser: 'New user', newUser: 'New user',
@ -203,5 +206,30 @@ export default {
recommendeDes: recommendeDes:
'Iconify component basically contains all icons. You can query any icon you want. And packaging will only package the icons used.', 'Iconify component basically contains all icons. You can query any icon you want. And packaging will only package the icons used.',
accessAddress: 'Access address' 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: '工作台', workplace: '工作台',
guide: '引导', guide: '引导',
component: '组件', component: '组件',
icon: '图标' icon: '图标',
echart: '图表',
countTo: '数字动画',
watermark: '水印'
}, },
analysis: { analysis: {
newUser: '新增用户', newUser: '新增用户',
@ -203,5 +206,29 @@ export default {
recommendeDes: recommendeDes:
'Iconify组件基本包含所有的图标你可以查询到你想要的任何图标。并且打包只会打包所用到的图标。', 'Iconify组件基本包含所有的图标你可以查询到你想要的任何图标。并且打包只会打包所用到的图标。',
accessAddress: '访问地址' 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: { meta: {
title: t('router.icon') 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 loading = ref(true)
const pieOptionsData = reactive<EChartsOption>(pieOptions) const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
// //
const getUserAccessSource = async () => { const getUserAccessSource = async () => {
@ -100,7 +100,7 @@ getAllApi()
<ElCol :xl="10" :lg="10" :md="24" :sm="24" :xs="24"> <ElCol :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
<ElCard shadow="hover" class="mb-20px"> <ElCard shadow="hover" class="mb-20px">
<ElSkeleton :loading="loading" animated> <ElSkeleton :loading="loading" animated>
<Echart :options="pieOptions" :height="300" /> <Echart :options="pieOptionsData" :height="300" />
</ElSkeleton> </ElSkeleton>
</ElCard> </ElCard>
</ElCol> </ElCol>

View File

@ -1,4 +1,5 @@
import { EChartsOption } from 'echarts' import { EChartsOption } from 'echarts'
import { EChartsOption as EChartsWordOption } from 'echarts-wordcloud'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
const { t } = 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
}
]
}
]
}