<template>
<div class="container">
<div ref="container" class="x6-graph"></div>
<div class="controls">
<button @click="zoomIn">放大</button>
<button @click="zoomOut">缩小</button>
<button @click="resetZoom">重置</button>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { Graph, Shape } from '@antv/x6'
import { Transform } from '@antv/x6-plugin-transform'
const container = ref(null)
let graph = null
// 初始化画布
const initGraph = () => {
graph = new Graph({
container: container.value,
width: 800,
height: 600,
grid: true,
mousewheel: {
enabled: true,
modifiers: 'ctrl'
},
interacting: {
nodeMovable: true
},
background: {
color: '#f5f7fa'
}
})
graph.use(new Transform({
resizing: true,
rotating: true
}))
createEditableOctagon()
createFixedScales()
graph.on('zoom', updateScaleLabels)
}
// 创建可编辑八边形
const createEditableOctagon = () => {
// 计算正八边形顶点坐标
const points = []
const radius = 50
for (let i = 0; i < 8; i++) {
const angle = (i * Math.PI) / 4
points.push({
x: 300 + radius * Math.cos(angle),
y: 200 + radius * Math.sin(angle)
})
}
graph.addNode({
shape: 'polygon',
x: 300,
y: 200,
width: 100,
height: 100,
attrs: {
body: {
fill: '#FEC55B',
stroke: '#333',
strokeWidth: 1,
points: points.map(p => [p.x, p.y])
},
label: {
text: '八边形',
fill: '#333'
}
},
editable: true,
transform: {
enabled: true,
preserveAspectRatio: false
},
selectable: true
})
}
// 创建固定刻度系统
const createFixedScales = () => {
// X轴刻度(顶部)
for (let x = 0; x <= graph.width(); x += 40) {
// 刻度线
graph.addNode({
id: `x-tick-${x}`,
shape: 'rect',
x,
y: 0,
width: 1,
height: 5,
attrs: {
body: { fill: '#666' }
},
selectable: false
})
// 标签(仅显示关键刻度)
if (x % 100 === 0) {
graph.addNode({
id: `x-label-${x}`,
shape: 'text',
x: x + 5,
y: 15,
attrs: {
label: { text: '' },
text: { fontSize: 10, fill: '#666' }
},
selectable: false
})
}
}
// Y轴刻度(右侧)
for (let y = 0; y <= graph.height(); y += 40) {
// 刻度线
graph.addNode({
id: `y-tick-${y}`,
shape: 'rect',
x: graph.width() - 5,
y,
width: 5,
height: 1,
attrs: {
body: { fill: '#666' }
},
selectable: false
})
// 标签(仅显示关键刻度)
if (y % 100 === 0) {
graph.addNode({
id: `y-label-${y}`,
shape: 'text',
x: graph.width() - 15,
y: y + 5,
attrs: {
label: { text: '' },
text: { fontSize: 10, fill: '#666' }
},
selectable: false
})
}
}
}
// 动态更新刻度标签
const updateScaleLabels = () => {
const zoom = graph.zoom()
const base = Math.pow(10, Math.floor(Math.log10(zoom * 100)))
const step = base * (zoom > 5 ? 1 : zoom > 1 ? 2 : 5)
// 更新X轴标签
for (let x = 0; x <= graph.width(); x += 40) {
if (x % 100 === 0) {
const logicalValue = Math.round(x / (40 * step)) * step
const node = graph.getCellById(`x-label-${x}`)
node.attr('label/text', logicalValue || '')
}
}
// 更新Y轴标签
for (let y = 0; y <= graph.height(); y += 40) {
if (y % 100 === 0) {
const logicalValue = Math.round(y / (40 * step)) * step
const node = graph.getCellById(`y-label-${y}`)
node.attr('label/text', logicalValue || '')
}
}
}
// 缩放控制
const zoomIn = () => graph.zoom(0.1)
const zoomOut = () => graph.zoom(-0.1)
const resetZoom = () => graph.zoomTo(1)
onMounted(() => {
initGraph()
})
</script>
<style scoped>
.container {
position: relative;
width: 100vw;
height: 100vh;
}
.x6-graph {
width: 100%;
height: 100%;
border: 1px solid #e0e0e0;
}
.controls {
position: absolute;
top: 20px;
left: 20px;
z-index: 1000;
}
button {
margin-right: 8px;
padding: 4px 8px;
background: #fff;
border: 1px solid #ddd;
cursor: pointer;
}
</style>,参考这个代码,这个可编辑多边形假设为八个点连接起来的封闭图形,在拖到这八个点时,多边形重新绘制形状,这个图形可以被拖拽,移动。底层画布可以自由拖动和缩放,且缩放时的X刻度线始终显示在画布的相对y为0的位置,,Y轴刻度线显示在画布的相对右侧位置,刻度线无法选中,给刻度线加上画布像素值的标签,类似1 2 3 4 6这样的,显示在刻度线缩放,一直到画布的宽高值,在缩放时,刻度线上的标签值也会动态变换,放大到最大显示 1,2 ,3这样显示,缩小时显示1 100 200这样
最新发布