網(wǎng)站建設(shè)優(yōu)化文章重慶今日頭條新聞消息
簡化需求:實現(xiàn)項目內(nèi)嵌人體模型,實現(xiàn)點擊不同部位彈出部位名稱
一:優(yōu)先3d,
方案:基于three.js,.gltf格式模型,vue3
缺點:合適且免費的3d模型找不到,因為項目對部位有要求。
注意:模型地址請使用絕對路徑。
效果圖:
代碼:
<template><div ref="canvasContainer" class="canvas-container"></div>
</template><script setup>
import * as THREE from 'three'
import { onMounted, ref } from 'vue'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'const canvasContainer = ref(null)onMounted(() => {let scene, camera, renderer, modellet raycaster = new THREE.Raycaster()let mouse = new THREE.Vector2()let selectedPart = nulllet isDragging = falselet previousMousePosition = { x: 0, y: 0 }const init = () => {// 創(chuàng)建場景scene = new THREE.Scene()scene.background = new THREE.Color(0xeeeeee)// 創(chuàng)建相機camera = new THREE.PerspectiveCamera(45, 500 / 500, 0.1, 1000)camera.position.set(0, 1.6, 3) // 相機位置// 創(chuàng)建渲染器,并設(shè)置大小為500px × 500pxrenderer = new THREE.WebGLRenderer({ antialias: true })renderer.setSize(500, 500)canvasContainer.value.appendChild(renderer.domElement)// 添加光源const light = new THREE.DirectionalLight(0xffffff, 1)light.position.set(5, 10, 7.5)scene.add(light)// 加載3D模型const loader = new GLTFLoader()loader.load('src/assets/models/b1_battle_droid/scene.gltf', (gltf) => {model = gltf.scenescene.add(model)})// 鼠標事件監(jiān)聽window.addEventListener('mousemove', onMouseMove)window.addEventListener('click', onClick)window.addEventListener('mousedown', onMouseDown)window.addEventListener('mouseup', onMouseUp)window.addEventListener('mousemove', onMouseMoveRotation)}const onMouseMove = (event) => {// 將鼠標位置標準化為Three.js坐標const rect = renderer.domElement.getBoundingClientRect()mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1raycaster.setFromCamera(mouse, camera)const intersects = raycaster.intersectObjects(scene.children, true)if (intersects.length > 0) {if (selectedPart) {// 恢復(fù)之前選中的部件顏色selectedPart.material.emissive.setHex(selectedPart.currentHex)}selectedPart = intersects[0].objectselectedPart.currentHex = selectedPart.material.emissive.getHex()selectedPart.material.emissive.setHex(0xff0000) // 懸浮變色} else if (selectedPart) {// 鼠標離開時恢復(fù)顏色selectedPart.material.emissive.setHex(selectedPart.currentHex)selectedPart = null}}const onClick = (event) => {if (selectedPart) {alert(`你點擊了: ${selectedPart.name}`)}}const onMouseDown = () => {isDragging = true}const onMouseUp = () => {isDragging = false}const onMouseMoveRotation = (event) => {if (isDragging) {const deltaMove = {x: event.clientX - previousMousePosition.x,y: event.clientY - previousMousePosition.y,}const rotationSpeed = 0.005model.rotation.y += deltaMove.x * rotationSpeedmodel.rotation.x += deltaMove.y * rotationSpeed}previousMousePosition = {x: event.clientX,y: event.clientY,}}const animate = () => {requestAnimationFrame(animate)renderer.render(scene, camera)}init()animate()
})
</script><style>
.canvas-container {width: 500px;height: 500px;overflow: hidden;margin: 0 auto;/* 居中對齊 */
}
</style>
方案二:差強人意選2d
方案:基于canvas,.png格式圖片,vue3
缺點:效果差一些,旋轉(zhuǎn)沒有了,身體部位區(qū)分做不到很細致。
注意:圖片地址import引入,再引用。
效果圖:
代碼:
<template><div><canvas ref="canvas" @click="handleClick"></canvas></div>
</template><script setup>
import { onMounted, ref } from 'vue'
import imgsrc from '@/assets/models/person.png'
const canvas = ref(null)
const bodyParts = [{ name: 'Head', x: 50, y: 30, width: 100, height: 100 },{ name: 'Chest', x: 50, y: 150, width: 100, height: 100 },{ name: 'Abdomen', x: 50, y: 270, width: 100, height: 100 },{ name: 'Legs', x: 50, y: 390, width: 100, height: 100 },
]onMounted(() => {handleImage()
})
const handleImage = () => {const ctx = canvas.value.getContext('2d')canvas.value.width = 200 // 設(shè)置 canvas 的寬度canvas.value.height = 500 // 設(shè)置 canvas 的高度const img = new Image()img.src = imgsrc // 使用 Vue 項目中的圖片路徑img.onload = function () {// 確保圖片加載完成后繪制到 canvas 上ctx.clearRect(0, 0, canvas.value.width, canvas.value.height) // 清空 canvasctx.drawImage(img, 0, 0, canvas.value.width, canvas.value.height) // 繪制圖片// 調(diào)試用:繪制點擊區(qū)域的邊框bodyParts.forEach((part) => {ctx.strokeStyle = 'red' // 用紅色邊框標記部位ctx.strokeRect(part.x, part.y, part.width, part.height)})}console.log('path is ' + img.src)
}
const handleClick = (event) => {const rect = canvas.value.getBoundingClientRect()const x = event.clientX - rect.leftconst y = event.clientY - rect.topconst clickedPart = bodyParts.find((part) => {return (x >= part.x &&x <= part.x + part.width &&y >= part.y &&y <= part.y + part.height)})if (clickedPart) {alert(`You clicked on: ${clickedPart.name}`)}
}
</script><style scoped>
canvas {border: 1px solid black;
}
</style>