Files
hospital-rescue-app-v2/uni_modules/tmx-ui/components/x-tree-flat/x-tree-flat.uvue
T
2026-09-24 16:25:22 +08:00

275 lines
7.8 KiB
Plaintext

<template>
<!-- #ifdef APP -->
<scroll-view
@scroll="onScrollTop"
class="xTreeFlatBox"
:scroll-top="scrollTop"
:scroll-y="true" direction="vertical" :style="{width:_width,height:_height}"
>
<scroll-view @scroll="onScrollLeft" :scroll-left="scrollLeft" :scroll-x="true" direction="horizontal" :style="{width: _width,height: canvasHeight+'px'}">
<canvas :key="keyids" @click="onclickCanvas" :id="id" ref="canvas" :style="{width:canvasWidth+'px',height:canvasHeight+'px'}"></canvas>
</scroll-view>
</scroll-view>
<!-- #endif -->
<!-- #ifdef MP -->
<view ref="xTreeFlatBox" class="xTreeFlatBox" :style="{width:_width,height:_height}">
<scroll-view @scroll="onScrollAll" class="xTreeFlatBoxScroll" :scroll-top="scrollTop" :scroll-left="scrollLeft" :scroll-x="true" :scroll-y="true" direction="all" :style="{width: '100%',height: '100%'}">
<canvas :key="keyids" @click="onclickCanvas" :id="id" ref="canvas" :style="{width:canvasWidth+'px',height:canvasHeight+'px'}"></canvas>
</scroll-view>
</view>
<!-- #endif -->
<!-- #ifdef WEB -->
<view ref="xTreeFlatBox" class="xTreeFlatBox" :style="{width:_width,height:_height}">
<canvas :key="keyids" @click="onclickCanvas" :id="id" ref="canvas" :style="{width:canvasWidth+'px',height:canvasHeight+'px'}"></canvas>
</view>
<!-- #endif -->
</template>
<script lang="ts" setup>
import { computed, ref, onMounted,PropType,getCurrentInstance,nextTick } from "vue"
import { xDate } from "../../core/util/xDate.uts"
import { checkIsCssUnit, getUnit } from "../../core/util/xCoreUtil.uts"
import { getDefaultColor } from "../../core/util/xCoreColorUtil.uts"
import { xConfig } from "../../config/xConfig.uts"
import { XTREEFLAT_NODES,XTreeFlatOpts } from "../../interface.uts"
import {XTREEFLAT_CONFIG,XTREEFLAT_CHILDREN,propsTypeAsSelef } from "./interface.uts"
import { OrgChartRenderer } from "./draw.uts"
/**
* @name 思维导图 xTreeFlat
* @page /pages/index/tree-flat
* @category 其它组件
* @description 主要用来展示平面树平面结构,思维导图的展示
* @constant 平台兼容
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
| --- | --- | --- | --- | --- | --- | --- | --- |
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
*/
defineOptions({name:"xTreeFlat"})
const xTreeFlatBox = ref<UniElement | null>(null)
const id = "xTreeFlat-"+Math.random().toString(16).substring(4,20)
const proxy = getCurrentInstance()?.proxy??null;
const scrollLeft = ref(0)
const scrollTop = ref(0)
const scrollLeft_onlyRead = ref(0)
const scrollTop_onlyRead = ref(0)
const boxNodeinfo = ref<NodeInfo|null>(null)
let tid = 23
const props = withDefaults(defineProps<propsTypeAsSelef>(),{
/**
* 画板宽,总宽不要小于节点展开后的宽,可以尽量设置大点
*/
canvasWidth:800,
/**
* 画板高,总高不要小于节点展开后的高,可以尽量设置大点
*/
canvasHeight:800,
/**
* 组件宽,可以为auto,百分比,数字字符,带单位字符
*/
width:'100%',
/**
* 组件高,不能为auto
*/
height:'600',
/**
* 动态数据
*/
list:[] as XTREEFLAT_NODES[],
/**
* 配置见类型:XTreeFlatOpts ,建议使用ref方法setData来设置
*/
opts:null as XTreeFlatOpts|null
})
const _width = computed(():string=>checkIsCssUnit(props.width,xConfig.unit))
const _height = computed(():string=>checkIsCssUnit(props.height,xConfig.unit))
const render = ref<null|OrgChartRenderer>(null)
const canvasWidth = ref(props.canvasWidth)
const canvasHeight = ref(props.canvasHeight)
const keyids = ref(23)
const emits = defineEmits([
/**
* 引擎初始化完成,可以进行通过ref来异步设置数据
*/
'init',
/** 当list数据被编辑变动时触发 */
'change',
/**
* 当前节点被点击时触发
* @param {item:XTREEFLAT_CHILDREN} 被点击的节点数据
*/
'click'
])
const setScrollPosition = ()=>{
// #ifdef WEB
let ele = xTreeFlatBox.value;
if(ele==null) return;
ele.scrollLeft = scrollLeft.value
ele.scrollTop = scrollTop.value
// #endif
}
/**
* 设置数据
* @param {XTREEFLAT_NODES[]} list 设置当前数据
*/
const setData = (list:XTREEFLAT_NODES[])=>{
if(render==null||boxNodeinfo.value==null){
console.error('render未初始化')
return;
}
render.value!.setData(list)
let dboxwidth = render.value!.getDrawBounds()
scrollTop_onlyRead.value = scrollTop.value
scrollLeft_onlyRead.value = scrollLeft.value
scrollTop.value = dboxwidth.y - (boxNodeinfo.value!.height!-dboxwidth.height)/2
scrollLeft.value = dboxwidth.x - (boxNodeinfo.value!.width!-dboxwidth.width)/2
setScrollPosition()
}
const onScrollTop = (evt:UniScrollEvent)=>{
scrollTop_onlyRead.value = evt.detail.scrollTop
}
const onScrollLeft = (evt:UniScrollEvent)=>{
scrollLeft_onlyRead.value = evt.detail.scrollLeft
}
const onScrollAll = (evt:UniScrollEvent)=>{
nextTick(()=>{
scrollTop_onlyRead.value = evt.detail.scrollTop
scrollLeft_onlyRead.value = evt.detail.scrollLeft
})
}
const onclickCanvas = (evt:UniPointerEvent)=>{
if(render.value==null||boxNodeinfo.value==null){
return;
}
// #ifdef WEB
let ele = xTreeFlatBox.value;
if(ele==null) return;
scrollTop_onlyRead.value = ele.scrollTop||0
scrollLeft_onlyRead.value = ele.scrollLeft||0
// #endif
render.value!.addEventClick(evt,scrollTop_onlyRead.value,scrollLeft_onlyRead.value)
}
const onRenderClick = (item:XTREEFLAT_CHILDREN)=>{
emits('click',item)
}
const onInit = ():Promise<any> =>{
return new Promise(()=>{
uni.createSelectorQuery()
.in(proxy)
.select(".xTreeFlatBox")
.boundingClientRect()
.exec(result=>{
if(result.length == 0) return;
let node = result[0]! as NodeInfo
canvasWidth.value = Math.max(props.canvasWidth,node.width!)
canvasHeight.value = Math.max(props.canvasHeight,node.height!)
keyids.value +=10
nextTick(()=>{
uni.createCanvasContextAsync({
id: id,
component: proxy,
success: (context : CanvasContext) => {
let opts = {} as XTreeFlatOpts
if(props.opts!=null){
opts = props.opts! as XTreeFlatOpts
}
render.value = new OrgChartRenderer( {
width:canvasWidth.value,
height:canvasHeight.value,
canvas:context,
nodeInfo:node,
bgColor:opts?.bgColor,
nodeBgColor:opts?.nodeBgColor,
fontColor:opts?.fontColor,
fontSize: opts?.fontSize,
lineColor:opts?.lineColor,
lineWidth:opts?.lineWidth,
padding: opts?.padding,
gutter:opts?.gutter,
parentLineGutter :opts?.parentLineGutter,
enbleOpenChildren :opts?.enbleOpenChildren,
nodeRadius : opts?.nodeRadius,
layout: opts?.layout
} )
boxNodeinfo.value = node
render.value!.onListen(onRenderClick)
if(props.list.length>0){
setData(props.list)
}
/**
* 引擎初始化完成,可以进行通过ref来异步设置数据
*/
emits('init')
}
})
})
})
})
}
watch(():any=>props.opts,()=>{
onInit()
},{deep:true})
onMounted(()=>{
clearTimeout(tid)
// #ifdef APP-ANDROID||APP-IOS||WEB
tid = setTimeout(function() {
onInit();
}, 50);
// #endif
// #ifdef APP-HARMONY
tid = setTimeout(function() {
onInit();
}, 100);
// #endif
})
// #ifdef MP
onReady(()=>{
onInit();
})
// #endif
onBeforeUnmount(()=>{
clearTimeout(tid)
})
defineExpose({
/**
* 设置树形组件的数据
* @description 用于动态设置或更新树形组件的数据源
* @param {XTREEFLAT_NODES[]} list - 树形节点数据数组
* @returns {void}
*/
setData
})
</script>
<style scoped>
.xTreeFlatBox{
position: relative;
/* #ifdef WEB */
overflow: auto;
/* #endif */
}
/* #ifdef MP||WEB */
.xTreeFlatBoxScroll{
position: absolute;
}
/* #endif */
</style>