Browse Source

InstancePointManager / LineSegmentManager 重构

master
修宁 6 months ago
parent
commit
d96597082d
  1. 408
      src/components/FabricView.vue
  2. 21
      src/editor/menus/Model3DView.ts
  3. 5
      src/router/index.ts
  4. 7
      src/types/fabricExtensions.d.ts

408
src/components/FabricView.vue

@ -1,408 +0,0 @@
<template>
<div class="fabric-view">
<el-space :gutter="10" class="toolbar">
<el-button @click="()=>performanceTest()">性能测试</el-button>
<el-button @click="selectAll">全选</el-button>
<div class="demo-color-block">
<span class="demonstration">物体数:<el-text type="danger">{{ restate.objects }}</el-text></span>
<span class="demonstration"> 顶点数:<el-text type="danger">{{ restate.vertices }}</el-text></span>
<span class="demonstration"> 三角形数:<el-text type="danger">{{ restate.faces }}</el-text></span>
</div>
</el-space>
<div class="main-content">
<div class="canvas-container" ref="canvasContainer" />
</div>
</div>
</template>
<script setup lang="ts">
import * as fabric from 'fabric'
import { nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
import Theme from '@/core/Theme.ts'
// DOM refs
const canvasContainer = ref(null)
const restate = reactive({
targetColor: '#ff0000',
loadScale: 1,
mode: 'translate',
objects: 0,
vertices: 0,
faces: 0
})
//
const state = {
showAxesHelper: true,
showGridHelper: true,
camera: {
position: { x: 0, y: 5, z: 10 },
rotation: { x: 0, y: 0, z: 0 }
}
}
onMounted(() => {
nextTick(() => {
initCanvas()
drawOriginMarker()
drawHelpGrid()
addPanAndZoomHandlers()
})
})
onBeforeUnmount(() => {
disposeFabric()
})
let canvas: fabric.Canvas
let resizeObserver: ResizeObserver | null = null
function initCanvas() {
const container = canvasContainer.value
if (!container) return
// fabric.Canvas
canvas = new fabric.Canvas(null, {
width: container.clientWidth,
height: container.clientHeight,
selection: true,
backgroundColor: Theme.backgroundColor
// preserveObjectStacking: true,
// renderOnAddRemove: false
})
container.appendChild(canvas.getElement())
canvas.enableMouseWheel = true
//
// canvas.setViewportTransform([1, 0, 0, 1, 0, 0])
canvas.requestRenderAll()
canvas.zoomToPoint(new fabric.Point(0, 0), 36)
const viewerDom = canvasContainer.value
if (resizeObserver) {
resizeObserver.unobserve(viewerDom)
}
resizeObserver = new ResizeObserver(handleResize)
resizeObserver.observe(viewerDom)
}
const handleResize = _.debounce(() => {
const container = canvasContainer.value //
if (container && canvas) {
const newWidth = container.clientWidth
const newHeight = container.clientHeight
// canvas
canvas.setDimensions({
width: newWidth,
height: newHeight
})
canvas.requestRenderAll()
}
}, 200)
function addPanAndZoomHandlers() {
const lowerCanvas = canvas.getElement()
let isDragging = false
let lastPosX = 0
let lastPosY = 0
let dragStartTransform = []
// 🔥
lowerCanvas.addEventListener('contextmenu', (e) => e.preventDefault())
// 使
lowerCanvas.addEventListener('mousedown', function(e) {
if (e.button === 2) { //
isDragging = true
lastPosX = e.clientX
lastPosY = e.clientY
dragStartTransform = [...canvas.viewportTransform]
}
})
lowerCanvas.addEventListener('mousemove', function(e) {
if (isDragging) {
const deltaX = e.clientX - lastPosX
const deltaY = e.clientY - lastPosY
// viewport
canvas.viewportTransform[4] = dragStartTransform[4] + deltaX
canvas.viewportTransform[5] = dragStartTransform[5] + deltaY
canvas.renderAll()
}
})
lowerCanvas.addEventListener('mouseup', function() {
isDragging = false
})
lowerCanvas.addEventListener('wheel', function(e) {
const delta = e.deltaY
let zoom = canvas.getZoom()
zoom *= 0.999 ** delta
if (zoom > 150) zoom = 150
if (zoom < 5) zoom = 5
canvas.zoomToPoint({ x: e.offsetX, y: e.offsetY }, zoom)
console.log('Zoom level:', zoom)
e.preventDefault()
e.stopPropagation()
}, { passive: false })
}
/**
* 绘制辅助网格线
*/
function drawHelpGrid() {
const step = 1
const xcount = 200
const ycount = 200
// -xcount/2 xcount/2 线, step
// -ycount/2 ycount/2 线, step
// Theme.helpGridLineColor
const halfWidth = (xcount / 2) * step
const halfHeight = (ycount / 2) * step
// 线X
for (let x = -halfWidth; x <= halfWidth; x += step) {
const line = new fabric.Line([x, -halfHeight, x, halfHeight], {
stroke: Theme.helpGridLineColor,
selectable: false,
evented: false,
strokeWidth: 0.05,
hasControls: false,
hasBorders: false
})
canvas.add(line)
}
// 线Y
for (let y = -halfHeight; y <= halfHeight; y += step) {
const line = new fabric.Line([-halfWidth, y, halfWidth, y], {
stroke: Theme.helpGridLineColor,
selectable: false,
evented: false,
strokeWidth: 0.05,
hasControls: false,
hasBorders: false
})
canvas.add(line)
}
canvas.renderAll()
}
function drawOriginMarker() {
const marker = new fabric.Circle({
radius: 5,
fill: 'red',
left: 0,
top: 0,
hasControls: false,
hasBorders: false,
lockMovementX: true,
lockMovementY: true,
selectable: false,
excludeFromExport: true,
objectCaching: false
})
marker.render = function(ctx) {
ctx.save()
ctx.translate(this.left, this.top)
ctx.beginPath()
ctx.arc(0, 0, 0.5, 0, Math.PI * 2, true)
ctx.fillStyle = 'red'
ctx.fill()
ctx.restore()
}
canvas.add(marker)
canvas.requestRenderAll()
}
function selectAll() {
const objects = canvas.getObjects().filter(obj => obj.selectable !== false)
const group = new fabric.Group(objects, {
originX: 'center',
originY: 'center'
})
canvas.setActiveObject(group)
canvas.requestRenderAll()
}
function disposeFabric() {
}
function performanceTest(count = 10) {
const spacing = 0.3
const nodes = []
debugger
//
for (let y = 0; y < count; y++) {
for (let x = 0; x < count; x++) {
const node = new fabric.Rect({
left: x * spacing,
top: y * spacing,
width: 10,
height: 10,
fill: 'blue',
originX: 'center',
originY: 'center',
hasControls: false,
hasBorders: false
})
canvas.add(node)
nodes.push(node)
}
}
// 线
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
const col = i % count
const row = Math.floor(i / count)
//
if (col < count - 1) {
const rightNode = nodes[i + 1]
const line = new fabric.Line(
[node.left, node.top, rightNode.left, rightNode.top],
{
stroke: 'black',
strokeWidth: 0.5,
selectable: false
}
)
canvas.add(line)
}
//
if (row < count - 1) {
const bottomNode = nodes[i + count]
const line = new fabric.Line(
[node.left, node.top, bottomNode.left, bottomNode.top],
{
stroke: 'black',
strokeWidth: 0.5,
selectable: false
}
)
canvas.add(line)
}
}
canvas.requestRenderAll()
}
function deleteSelected() {
const activeObj = canvas.getActiveObject()
if (!activeObj) return
if (activeObj.type === 'group') {
const g: fabric.Group = activeObj
g.getObjects().forEach(obj => canvas.remove(obj))
} else {
canvas.remove(activeObj)
}
canvas.discardActiveObject()
canvas.requestRenderAll()
}
fabric.Canvas.prototype.rateRule = 1
fabric.Canvas.prototype.toPixel = function(value) {
return value * this.rateRule
}
fabric.Canvas.prototype.toUnit = function(value, unit = 'cm') {
return value / this.rateRule
}
</script>
<style scoped lang="less">
.fabric-view {
display: flex;
flex-direction: column;
flex-grow: 1;
overflow: hidden;
.canvas-left-toolbar {
position: absolute;
left: 5px;
top: 5px;
width: 32px;
background: #eee;
text-align: center;
button {
color: #555;
background-color: #ddd;
border: 0;
margin: 0;
padding: 5px 8px;
font-size: 12px;
text-transform: uppercase;
cursor: pointer;
outline: none;
}
button.selected {
background-color: #fff;
}
}
.toolbar {
padding: 10px;
background: #f5f5f5;
border-bottom: 1px solid #ccc;
}
.dialog-container {
display: flex;
flex-direction: column;
height: 100vh;
}
.main-content {
display: flex;
flex: 1;
overflow: hidden;
.model3d-content {
height: 100%;
display: flex;
flex-direction: row;
}
}
.canvas-container {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.model3d-gui-wrap {
border-left: 1px solid #ccc;
background: #111;
width: 100%;
height: 100%;
overflow-y: auto;
}
.gui-panel {
:deep(.lil-gui.root) {
width: 100%;
}
}
}
</style>

21
src/editor/menus/Model3DView.ts

@ -1,6 +1,5 @@
import { defineMenu } from '@/runtime/DefineMenu.ts' import { defineMenu } from '@/runtime/DefineMenu.ts'
import Model3DView from '@/components/Model3DView.vue' import Model3DView from '@/components/Model3DView.vue'
import FabricView from '@/components/FabricView.vue'
import ThreePerfView from '@/components/ThreePerfView.vue' import ThreePerfView from '@/components/ThreePerfView.vue'
export default defineMenu((menus) => { export default defineMenu((menus) => {
@ -25,26 +24,10 @@ export default defineMenu((menus) => {
} }
}, },
{ {
name: 'fabricView', label: 'Fabric查看器', order: 2, name: 'threePerfView', label: '性能测试', order: 3,
click: () => {
system.showDialog(FabricView, {
title: 'Fabric查看器',
width: 950,
height: 400,
showClose: true,
showMax: true,
showCancelButton: false,
showOkButton: false,
dialogClass: 'fabric-view-wrap',
data: { fabricView: true }
})
}
},
{
name: 'threePerfView', label: 'ThreePerf查看器', order: 3,
click: () => { click: () => {
system.showDialog(ThreePerfView, { system.showDialog(ThreePerfView, {
title: 'Fabric查看器', title: '性能测试',
width: 950, width: 950,
height: 400, height: 400,
showClose: true, showClose: true,

5
src/router/index.ts

@ -10,11 +10,6 @@ const router = createRouter({
redirect: '/editor' redirect: '/editor'
}, },
{ {
path: '/fabric',
name: 'fabric',
component: () => import('@/components/FabricView.vue')
},
{
path: '/tp', path: '/tp',
name: 'tp', name: 'tp',
component: () => import('@/components/ThreePerfView.vue') component: () => import('@/components/ThreePerfView.vue')

7
src/types/fabricExtensions.d.ts

@ -1,7 +0,0 @@
import 'fabric'
declare module 'fabric' {
interface Canvas {
enableMouseWheel: boolean
}
}
Loading…
Cancel
Save