| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- import { ref } from 'vue'
- import { TransformControler } from '../demo/lmm/controler/TransformControler'
- import { OrbitControler } from '../demo/lmm/controler/OrbitControler'
- import { Scene } from '../demo/lmm/core/Scene'
- import { Group } from '../demo/lmm/objects/Group'
- import { Img2D } from '../demo/lmm/objects/Img2D'
- import { Vector2 } from '../demo/lmm/math/Vector2'
- import { EventDispatcher } from '../demo/lmm/core/EventDispatcher'
- import { SelectObj } from '../demo/lmm/objects/ObjectUtils'
- import { Object2D } from '../demo/lmm/objects/Object2D'
- class Editor extends EventDispatcher {
- /* 编辑器场景 */
- editorScene = new Scene()
- /* 编辑器中的图案 */
- group = new Group()
- /* 图案控制器 */
- transformControler = new TransformControler()
- /* 相机轨道控制器 */
- orbitControler = new OrbitControler(this.editorScene.camera)
- /* 鼠标划入的图形 */
- objHover: Object2D | null = null
- /* 鼠标状态 */
- cursor = ref('default')
- /* 设计尺寸 */
- designSize = 0
- /* 设计图 */
- designImg = new Img2D({
- index: 1000,
- })
- /* 虚拟场景 */
- resultScene = new Scene()
- /* 虚拟场景里的图案集合 */
- resultGroup = new Group()
- constructor() {
- super()
- const {
- editorScene,
- orbitControler,
- group,
- transformControler,
- designImg,
- resultScene,
- resultGroup,
- } = this
- /* 编辑器场景*/
- editorScene.add(group, transformControler, designImg)
- /* 虚拟场景 */
- resultScene.add(resultGroup)
- /* 渲染编辑器和虚拟场景 */
- transformControler.addEventListener('change', () => {
- this.render()
- })
- orbitControler.addEventListener('change', () => {
- this.render()
- })
- /* 虚拟场景的图案同步编辑器场景的图案 */
- // 添加图案
- group.addEventListener('add', ({ obj }) => {
- if (obj instanceof Img2D) {
- const { image, position, rotate, scale, offset, size, uuid } = obj
- resultGroup.add(
- new Img2D({
- image,
- position,
- rotate,
- scale,
- offset,
- size,
- uuid,
- })
- )
- }
- })
- // 变换图案
- transformControler.addEventListener('transformed', ({ obj }) => {
- const { position, rotate, scale, offset } = obj
- const resultImg = resultGroup.children[group.children.indexOf(obj)]
- if (resultImg instanceof Img2D) {
- resultImg.setOption({
- position,
- rotate,
- scale,
- offset,
- })
- }
- })
- // 删除图案
- group.addEventListener('remove', ({ obj }) => {
- resultGroup.getObjectByProperty('uuid', obj.uuid)?.remove()
- })
- }
- onMounted(editorDom: HTMLDivElement, effectDom: HTMLDivElement) {
- const {
- editorScene: { canvas },
- resultScene: { canvas: resultCanvas },
- resultGroup,
- } = this
- /* 编辑器 */
- editorDom.append(canvas)
- const { clientWidth: dx, clientHeight: dy } = editorDom
- canvas.width = dx
- canvas.height = dy
- /* 设计尺寸 */
- const designSize = Math.min(dx, dy) * 0.5
- this.designSize = designSize
- /* 编辑器事件监听 */
- canvas.addEventListener('pointerdown', this.pointerdown.bind(this))
- canvas.addEventListener('pointermove', this.pointermove.bind(this))
- window.addEventListener('pointerup', this.pointerup.bind(this))
- window.addEventListener('keydown', this.keydown.bind(this))
- window.addEventListener('keyup', this.keyup.bind(this))
- canvas.addEventListener('wheel', this.wheel.bind(this))
- canvas.addEventListener('contextmenu', this.contextmenu.bind(this))
- /* 虚拟场景 */
- const { clientWidth: fx, clientHeight: fy } = effectDom
- resultCanvas.width = fx
- resultCanvas.height = fy
- resultGroup.setOption({
- scale: new Vector2(fx / designSize),
- position: new Vector2(0, fx * 0.12),
- })
- }
- onUnmounted() {
- const {
- editorScene: { canvas },
- } = this
- /* 删除canvas,避免onMounted时重复添加 */
- canvas.remove()
- /* 取消事件监听 */
- canvas.removeEventListener('pointerdown', this.pointerdown)
- canvas.removeEventListener('pointermove', this.pointermove)
- window.removeEventListener('pointerup', this.pointerup)
- window.removeEventListener('keydown', this.keydown)
- window.removeEventListener('keyup', this.keyup)
- canvas.removeEventListener('wheel', this.wheel)
- canvas.removeEventListener('contextmenu', this.contextmenu)
- }
- /* 鼠标按下 */
- pointerdown(event: PointerEvent) {
- const { editorScene, transformControler, group, orbitControler } = this
- const { button, clientX, clientY } = event
- const mp = editorScene.clientToClip(clientX, clientY)
- switch (button) {
- case 0:
- this.objHover = SelectObj(editorScene)(group.children, mp)
- transformControler.pointerdown(this.objHover, mp)
- this.updateMouseCursor()
- break
- case 1:
- orbitControler.pointerdown(clientX, clientY)
- break
- }
- }
- /* 鼠标移动 */
- pointermove(event: PointerEvent) {
- const { editorScene, transformControler, group, orbitControler } = this
- const { clientX, clientY } = event
- const mp = editorScene.clientToClip(clientX, clientY)
- orbitControler.pointermove(clientX, clientY)
- transformControler.pointermove(mp)
- this.objHover = SelectObj(editorScene)(group.children, mp)
- this.updateMouseCursor()
- }
- /* 鼠标抬起 */
- pointerup({ button }: PointerEvent) {
- switch (button) {
- case 0:
- this.transformControler.pointerup()
- break
- case 1:
- this.orbitControler.pointerup()
- break
- }
- }
- /* 键盘按下 */
- keydown({ key, altKey, shiftKey }: KeyboardEvent) {
- this.transformControler.keydown(key, altKey, shiftKey)
- this.updateMouseCursor()
- }
- /* 键盘抬起 */
- keyup({ altKey, shiftKey }: KeyboardEvent) {
- this.transformControler.keyup(altKey, shiftKey)
- }
- /* 滑动滚轮 */
- wheel({ deltaY }: WheelEvent) {
- this.orbitControler.doScale(deltaY)
- }
- /* 取消右键的默认功能 */
- contextmenu(event: MouseEvent) {
- event.preventDefault()
- }
- /* 更新鼠标样式 */
- updateMouseCursor() {
- const { transformControler, cursor, objHover } = this
- if (transformControler.mouseState) {
- cursor.value = 'none'
- } else if (objHover) {
- cursor.value = 'pointer'
- } else {
- cursor.value = 'default'
- }
- }
- /* 设计图和效果图的渲染 */
- render() {
- this.editorScene.render()
- this.resultScene.render()
- this.dispatchEvent({ type: 'render' })
- }
- /* 添加图案 */
- addImg(image: HTMLImageElement) {
- const {
- group: { children },
- } = this
- /* 图案序号,基于最大序号递增 */
- const maxNum = Math.max(...children.map((obj) => obj.layerNum))
- const layerNum = (children.length ? maxNum : 0) + 1
- /* 建立Img2D对象 */
- const img2D = new Img2D({
- image,
- layerNum,
- name: '图层' + layerNum,
- })
- /* 基于设计尺寸设置图案尺寸 */
- this.setImg2DSize(img2D, 0.5)
- /* 添加图案 */
- this.group.add(img2D)
- /* 选择图案 */
- this.transformControler.obj = img2D
- return img2D
- }
- /* 设置图案尺寸 */
- setImg2DSize(img2D: Img2D, ratio = 1) {
- const { designSize } = this
- const { width, height } = img2D.image as HTMLImageElement
- const w = designSize * ratio
- const h = (w * width) / height
- img2D.size.set(w, h)
- img2D.offset.set(-w / 2, -h / 2)
- }
- /* 配置设计图 */
- setDesignImg(src: string) {
- const { designImg, designSize } = this
- /* 图案尺寸随设计尺寸而定,位置居中 */
- designImg.setOption({
- src,
- size: new Vector2(designSize),
- offset: new Vector2(-designSize / 2),
- })
- /* 渲染 */
- ; (designImg.image as HTMLImageElement).onload = () => {
- this.editorScene.render()
- }
- }
- /* 基于uuid 选择图案 */
- selectImgByUUID(uuid: string) {
- const { group, transformControler } = this
- const obj = group.getObjectByProperty('uuid', uuid)
- if (obj instanceof Img2D) {
- transformControler.obj = obj
- }
- }
- /* 基于图案索引置换图案 */
- replaceImg(a: number, b: number) {
- const { group, resultGroup } = this
- for (let { children } of [group, resultGroup]) {
- ;[children[a], children[b]] = [children[b], children[a]]
- }
- this.render()
- }
- }
- export { Editor }
|