275 lines
7.8 KiB
Plaintext
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> |