feat: Add count-to demo
feat: Add useWatermark hook and add useWatermark demo
This commit is contained in:
parent
e4b7a76912
commit
d3fbd3a06c
|
@ -8,9 +8,7 @@ export const usePageLoading = () => {
|
|||
}
|
||||
|
||||
const loadDone = () => {
|
||||
setTimeout(() => {
|
||||
appStore.setPageLoading(false)
|
||||
}, 1000)
|
||||
appStore.setPageLoading(false)
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -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 }
|
||||
}
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: '重置水印'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue