0.7.0.0
This commit is contained in:
@@ -312,12 +312,50 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
|
||||
chartRef.current.innerHTML = ''
|
||||
}
|
||||
|
||||
// iOS/iPadOS 检测(包括 Safari、Chrome 等所有浏览器)
|
||||
// iPad 上所有浏览器都使用 WebKit 引擎
|
||||
const container = chartRef.current
|
||||
const isTouchDevice = navigator.maxTouchPoints > 1
|
||||
const isWebKit = /AppleWebKit/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent)
|
||||
const isIOSChrome = /CriOS/.test(navigator.userAgent)
|
||||
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
|
||||
(navigator.platform === 'MacIntel' && isTouchDevice) ||
|
||||
isIOSChrome
|
||||
|
||||
console.log('Device detection:', { isIOS, isTouchDevice, isWebKit, isIOSChrome, userAgent: navigator.userAgent })
|
||||
|
||||
// 对于 iOS,设置明确的像素高度
|
||||
if (isIOS) {
|
||||
const headerHeight = 120
|
||||
const calculatedHeight = window.innerHeight - headerHeight
|
||||
container.style.height = `${calculatedHeight}px`
|
||||
}
|
||||
|
||||
const data = convertToChartData()
|
||||
|
||||
// 获取容器实际尺寸 - iOS Safari 可能返回 0,所以使用 window 尺寸作为后备
|
||||
const containerRect = chartRef.current.getBoundingClientRect()
|
||||
let containerWidth = containerRect.width
|
||||
let containerHeight = containerRect.height
|
||||
|
||||
// 如果尺寸无效,使用 window 尺寸
|
||||
if (!containerWidth || containerWidth < 100) {
|
||||
containerWidth = window.innerWidth
|
||||
}
|
||||
if (!containerHeight || containerHeight < 100) {
|
||||
containerHeight = window.innerHeight - 120
|
||||
}
|
||||
|
||||
console.log('D3 Chart container size:', { containerWidth, containerHeight, isIOS })
|
||||
|
||||
// 初始化图表
|
||||
const chart = new OrgChart()
|
||||
.container(chartRef.current)
|
||||
.data(data)
|
||||
.svgWidth(containerWidth)
|
||||
.svgHeight(containerHeight)
|
||||
.scaleExtent([0.1, 2]) // 缩放范围
|
||||
.initialZoom(0.5) // 初始缩放级别
|
||||
.nodeWidth((d: any) => {
|
||||
const spouseCount = d.data.spouseCount || 0
|
||||
return spouseCount === 0 ? 170 : spouseCount === 1 ? 300 : 170 + spouseCount * 110
|
||||
@@ -425,9 +463,11 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
-webkit-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
"
|
||||
onmouseover="this.style.boxShadow='0 12px 40px rgba(0,0,0,0.15)'; this.style.transform='translateY(-4px) scale(1.02)'"
|
||||
onmouseout="this.style.boxShadow='0 4px 20px rgba(0,0,0,0.08)'; this.style.transform='translateY(0) scale(1)'"
|
||||
onmouseout="this.style.boxShadow='0 4px 20px rgba(0,0,0,0.08)'; this.style.transform='translateZ(0)'"
|
||||
>
|
||||
<!-- 顶部装饰条 -->
|
||||
<div style="
|
||||
@@ -661,6 +701,54 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
|
||||
.expandAll() // 初始化时展开所有节点
|
||||
.fit() // 自适应全图显示
|
||||
|
||||
// 延迟再次 fit
|
||||
setTimeout(() => chart.fit(), 100)
|
||||
setTimeout(() => chart.fit(), 300)
|
||||
|
||||
// 所有触摸设备都需要特殊处理 - iOS foreignObject bug 修复
|
||||
if (isTouchDevice) {
|
||||
setTimeout(() => {
|
||||
const w = window.innerWidth
|
||||
const h = window.innerHeight - 120
|
||||
|
||||
if (chartRef.current) {
|
||||
chartRef.current.style.height = `${h}px`
|
||||
chartRef.current.style.width = `${w}px`
|
||||
|
||||
// iOS foreignObject bug 修复:强制重绘 SVG
|
||||
const svg = chartRef.current.querySelector('svg')
|
||||
if (svg) {
|
||||
// 触发重绘
|
||||
svg.style.display = 'none'
|
||||
void (svg as any).getBBox() // 强制回流
|
||||
svg.style.display = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 重新设置 SVG 尺寸并渲染
|
||||
chart.svgWidth(w).svgHeight(h).render().expandAll().fit()
|
||||
console.log('Touch device delayed render:', { w, h })
|
||||
}, 500)
|
||||
|
||||
// 再次强制重绘
|
||||
setTimeout(() => {
|
||||
if (chartRef.current) {
|
||||
const svg = chartRef.current.querySelector('svg')
|
||||
if (svg) {
|
||||
svg.style.transform = 'translateZ(0)'
|
||||
// 强制所有 foreignObject 重新定位
|
||||
const foreignObjects = svg.querySelectorAll('foreignObject')
|
||||
foreignObjects.forEach((fo: Element) => {
|
||||
(fo as HTMLElement).style.transform = 'translateZ(0)'
|
||||
})
|
||||
}
|
||||
}
|
||||
chart.fit()
|
||||
}, 1000)
|
||||
|
||||
setTimeout(() => chart.fit(), 1500)
|
||||
}
|
||||
|
||||
// 注册全局配偶点击处理函数
|
||||
window.d3ChartSpouseClick = (event: Event, spouseId: string) => {
|
||||
event.stopPropagation()
|
||||
@@ -708,6 +796,27 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
|
||||
}
|
||||
}, [members, rootId, onMemberClick, avatarCache])
|
||||
|
||||
// 监听窗口大小变化,重新适应视图
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
if (chartInstanceRef.current) {
|
||||
// 延迟执行 fit,等待布局稳定
|
||||
setTimeout(() => {
|
||||
chartInstanceRef.current?.fit()
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('resize', handleResize)
|
||||
// 监听屏幕方向变化(iPad 等设备)
|
||||
window.addEventListener('orientationchange', handleResize)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
window.removeEventListener('orientationchange', handleResize)
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 监听 selectedMembers 变化,通过 DOM 操作更新选中标记
|
||||
useEffect(() => {
|
||||
console.log('Selection useEffect triggered, selectedMembers:', selectedMembers, 'isReady:', isReady)
|
||||
@@ -825,12 +934,11 @@ const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
|
||||
}))
|
||||
|
||||
return (
|
||||
<div className="w-full h-full bg-[url('https://www.transparenttextures.com/patterns/rice-paper.png')] bg-repeat relative" key={`d3-chart-${rootId}`}>
|
||||
<div className="w-full h-full bg-[url('https://www.transparenttextures.com/patterns/rice-paper.png')] bg-repeat relative overflow-hidden" key={`d3-chart-${rootId}`}>
|
||||
{/* 图表容器 */}
|
||||
<div
|
||||
ref={chartRef}
|
||||
className="w-full h-full"
|
||||
style={{ overflow: 'hidden' }}
|
||||
/>
|
||||
|
||||
{/* 自定义右键菜单 */}
|
||||
|
||||
Reference in New Issue
Block a user