forked from github/dataease
feat(数据大屏): 数据大屏增加刻度尺指示功能
This commit is contained in:
parent
d1466f511c
commit
486d1f03a4
1
core/core-frontend/src/assets/svg/dv-ruler.svg
Normal file
1
core/core-frontend/src/assets/svg/dv-ruler.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1719155593625" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="32183" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M658.52 0v658.52H0V1024h1024V0H658.52z m23.1 991.3V835.18h-32.7V991.3H465.31V790.06h-32.7V991.3H249.02V835.18h-32.7V991.3H32.7V691.22h658.52V32.7H991.3v183.61H835.18v32.7H991.3v183.61H790.06v32.7H991.3v183.59H835.18v32.7H991.3v309.68H681.62z" p-id="32184"></path></svg>
|
After Width: | Height: | Size: 604 B |
@ -157,6 +157,7 @@ onUnmounted(() => {
|
||||
background-color: @side-area-background;
|
||||
border-top: 1px solid @side-outline-border-color;
|
||||
color: #fff;
|
||||
z-index: 2;
|
||||
transition: 0.5s;
|
||||
.scale-area {
|
||||
display: flex;
|
||||
|
@ -8,6 +8,14 @@ const props = defineProps({
|
||||
tickLabelFormatter: {
|
||||
type: Function,
|
||||
default: value => value.toString() // 刻度标签格式化函数,默认直接转为字符串
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 300 // 尺子方向
|
||||
},
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'horizontal' // 尺子方向
|
||||
}
|
||||
})
|
||||
|
||||
@ -15,10 +23,14 @@ const labelInterval = 5
|
||||
|
||||
const { canvasStyleData } = storeToRefs(dvMainStore)
|
||||
|
||||
const rulerSize = computed(() =>
|
||||
props.direction === 'horizontal' ? canvasStyleData.value.width : canvasStyleData.value.height
|
||||
)
|
||||
|
||||
const ticks = computed(() => {
|
||||
const result = []
|
||||
let currentValue = 0
|
||||
while (currentValue <= canvasStyleData.value.width) {
|
||||
while (currentValue <= rulerSize.value) {
|
||||
const isLong = currentValue % (labelInterval * tickSize.value) === 0
|
||||
const label = isLong ? props.tickLabelFormatter(currentValue) : ''
|
||||
result.push({ position: (currentValue * canvasStyleData.value.scale) / 100, label, isLong })
|
||||
@ -29,28 +41,47 @@ const ticks = computed(() => {
|
||||
|
||||
const wStyle = computed(() => {
|
||||
return {
|
||||
width: canvasStyleData.value.width * 1.5 + 'px'
|
||||
width: rulerSize.value * 1.5 + 'px'
|
||||
}
|
||||
})
|
||||
|
||||
const radio = computed(() => rulerSize.value / canvasStyleData.value.width)
|
||||
const tickSize = computed(
|
||||
() =>
|
||||
10 *
|
||||
Math.max(Math.floor(200000 / (canvasStyleData.value.width * canvasStyleData.value.scale)), 1)
|
||||
Math.max(
|
||||
Math.floor((200000 * radio.value) / (rulerSize.value * canvasStyleData.value.scale)),
|
||||
1
|
||||
)
|
||||
)
|
||||
|
||||
const scaleWidth = computed(() => (canvasStyleData.value.width * canvasStyleData.value.scale) / 100)
|
||||
const scaleWidth = computed(() => (rulerSize.value * canvasStyleData.value.scale) / 100)
|
||||
|
||||
const rulerScroll = e => {
|
||||
wRuleRef.value.scrollTo(e.scrollLeft, 0)
|
||||
const left = props.direction === 'vertical' ? e.scrollTop : e.scrollLeft
|
||||
wRuleRef.value.scrollTo(left, 0)
|
||||
}
|
||||
|
||||
const outerStyle = computed(() => {
|
||||
return {
|
||||
width: props.direction === 'vertical' ? props.size - 30 + 'px' : '100%'
|
||||
}
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
rulerScroll
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="ruler-outer" ref="wRuleRef">
|
||||
<div
|
||||
class="ruler-outer"
|
||||
:style="outerStyle"
|
||||
:class="{ 'ruler-vertical': direction === 'vertical' }"
|
||||
ref="wRuleRef"
|
||||
>
|
||||
<!--覆盖着尺子上方防止鼠标移到尺子位置滑动-->
|
||||
<div class="ruler-shadow" :style="outerStyle"></div>
|
||||
<div :style="wStyle" class="ruler-outer-scroll">
|
||||
<div class="ruler" :style="{ width: `${scaleWidth}px` }">
|
||||
<div class="ruler-line" :style="{ width: `${scaleWidth}px` }"></div>
|
||||
@ -73,8 +104,36 @@ defineExpose({
|
||||
width: 0px !important;
|
||||
height: 0px !important;
|
||||
}
|
||||
.ruler-vertical {
|
||||
position: absolute;
|
||||
left: 30px;
|
||||
top: 30px;
|
||||
transform-origin: top left;
|
||||
transform: rotate(90deg);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
z-index: 1;
|
||||
.ruler {
|
||||
.ruler-line {
|
||||
top: 0;
|
||||
}
|
||||
.ruler-tick {
|
||||
top: 0;
|
||||
.tick-label {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ruler-shadow {
|
||||
position: absolute;
|
||||
height: 30px;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ruler-outer {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
background-color: #2c2c2c;
|
||||
}
|
||||
|
@ -0,0 +1,144 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const wRuleRef = ref(null)
|
||||
const props = defineProps({
|
||||
tickLabelFormatter: {
|
||||
type: Function,
|
||||
default: value => value.toString() // 刻度标签格式化函数,默认直接转为字符串
|
||||
},
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'horizontal' // 尺子方向
|
||||
}
|
||||
})
|
||||
|
||||
const labelInterval = 5
|
||||
|
||||
const { canvasStyleData } = storeToRefs(dvMainStore)
|
||||
|
||||
const ticks = computed(() => {
|
||||
const result = []
|
||||
let currentValue = 0
|
||||
while (currentValue <= canvasStyleData.value.height) {
|
||||
const isLong = currentValue % (labelInterval * tickSize.value) === 0
|
||||
const label = isLong ? props.tickLabelFormatter(currentValue) : ''
|
||||
result.push({ position: (currentValue * canvasStyleData.value.scale) / 100, label, isLong })
|
||||
currentValue += tickSize.value
|
||||
}
|
||||
return result
|
||||
})
|
||||
|
||||
const hStyle = computed(() => {
|
||||
return {
|
||||
height: canvasStyleData.value.height * 1.5 + 'px'
|
||||
}
|
||||
})
|
||||
const tickSize = computed(
|
||||
() =>
|
||||
10 *
|
||||
Math.max(Math.floor(200000 / (canvasStyleData.value.height * canvasStyleData.value.scale)), 1)
|
||||
)
|
||||
|
||||
const scaleHeight = computed(
|
||||
() => (canvasStyleData.value.height * canvasStyleData.value.scale) / 100
|
||||
)
|
||||
|
||||
const rulerScroll = e => {
|
||||
wRuleRef.value.scrollTo(0, e.scrollHeight)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
rulerScroll
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="ruler-outer-vertical" ref="wRuleRef">
|
||||
testtest
|
||||
<!--覆盖着尺子上方防止鼠标移到尺子位置滑动-->
|
||||
<div class="ruler-shadow-vertical"></div>
|
||||
<div :style="hStyle" class="ruler-outer-vertical-scroll">
|
||||
<div class="ruler" :style="{ height: `${scaleHeight}px` }">
|
||||
<div class="ruler-line" :style="{ height: `${scaleHeight}px` }"></div>
|
||||
<div
|
||||
v-for="(tick, index) in ticks"
|
||||
:key="index"
|
||||
class="ruler-tick"
|
||||
:class="{ 'long-tick': tick.isLong }"
|
||||
:style="{ left: `${tick.position}px` }"
|
||||
>
|
||||
<span v-if="tick.isLong" class="tick-label">{{ tick.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
::-webkit-scrollbar {
|
||||
width: 0px !important;
|
||||
height: 0px !important;
|
||||
}
|
||||
.ruler-shadow-vertical {
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ruler-outer-vertical {
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
background-color: #2c2c2c;
|
||||
}
|
||||
|
||||
.ruler-outer-vertical-scroll {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.ruler {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
height: 100%;
|
||||
border-left: 1px solid #974e4e;
|
||||
background-color: #2c2c2c;
|
||||
}
|
||||
|
||||
.ruler-line {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 1px;
|
||||
background-color: #ac2a2a;
|
||||
}
|
||||
|
||||
.ruler-tick {
|
||||
position: absolute;
|
||||
bottom: 1px;
|
||||
height: 3px;
|
||||
width: 1px;
|
||||
background-color: #e38a8a;
|
||||
}
|
||||
|
||||
.long-tick {
|
||||
width: 1px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.tick-label {
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
font-size: 8px;
|
||||
left: 50%;
|
||||
transform: translateX(2%);
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
@ -65,6 +65,7 @@ const contextmenuStore = contextmenuStoreWithOut()
|
||||
const composeStore = composeStoreWithOut()
|
||||
const canvasCacheOutRef = ref(null)
|
||||
const deWRulerRef = ref(null)
|
||||
const deHRulerRef = ref(null)
|
||||
|
||||
const {
|
||||
fullscreenFlag,
|
||||
@ -82,6 +83,7 @@ const canvasInner = ref(null)
|
||||
const leftSidebarRef = ref(null)
|
||||
const dvLayout = ref(null)
|
||||
const canvasCenterRef = ref(null)
|
||||
const mainHeight = ref(300)
|
||||
const state = reactive({
|
||||
datasetTree: [],
|
||||
scaleHistory: null,
|
||||
@ -179,9 +181,9 @@ const initScroll = () => {
|
||||
nextTick(() => {
|
||||
const { width, height } = canvasStyleData.value
|
||||
const mainWidth = canvasCenterRef.value.clientWidth
|
||||
const mainHeight = canvasCenterRef.value.clientHeight
|
||||
mainHeight.value = canvasCenterRef.value.clientHeight
|
||||
const scrollX = (1.5 * width - mainWidth) / 2
|
||||
const scrollY = (1.5 * height - mainHeight) / 2 + 20
|
||||
const scrollY = (1.5 * height - mainHeight.value) / 2 + 20
|
||||
// 设置画布初始滚动条位置
|
||||
canvasOut.value.scrollTo(scrollX, scrollY)
|
||||
})
|
||||
@ -361,7 +363,9 @@ const viewsPropertiesShow = computed(
|
||||
|
||||
const scrollCanvas = e => {
|
||||
deWRulerRef.value.rulerScroll(e)
|
||||
deHRulerRef.value.rulerScroll(e)
|
||||
}
|
||||
|
||||
eventBus.on('handleNew', handleNew)
|
||||
</script>
|
||||
|
||||
@ -393,7 +397,13 @@ eventBus.on('handleNew', handleNew)
|
||||
</dv-sidebar>
|
||||
<!-- 中间画布 -->
|
||||
<main id="dv-main-center" class="center" ref="canvasCenterRef">
|
||||
<div class="de-ruler-icon-outer">
|
||||
<el-icon class="de-ruler-icon">
|
||||
<Icon name="dv-ruler" />
|
||||
</el-icon>
|
||||
</div>
|
||||
<de-ruler ref="deWRulerRef"></de-ruler>
|
||||
<de-ruler direction="vertical" :size="mainHeight" ref="deHRulerRef"></de-ruler>
|
||||
<el-scrollbar
|
||||
ref="canvasOut"
|
||||
@scroll="scrollCanvas"
|
||||
@ -554,4 +564,19 @@ eventBus.on('handleNew', handleNew)
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.de-ruler-icon-outer {
|
||||
background: #2c2c2c;
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
z-index: 3;
|
||||
color: #ebebeb;
|
||||
.de-ruler-icon {
|
||||
margin-left: 6px;
|
||||
margin-top: 6px;
|
||||
font-size: 24px;
|
||||
color: #ebebeb;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user