TransformControler.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <script setup lang="ts">
  2. import { ref, onMounted } from 'vue'
  3. import { TransformControler } from '../lmm/controler/TransformControler'
  4. import { OrbitControler } from '../lmm/controler/OrbitControler'
  5. import { Scene } from '../lmm/core/Scene'
  6. import { Vector2 } from '../lmm/math/Vector2'
  7. import { Group } from '../lmm/objects/Group'
  8. import { ImagePromises, SelectObj } from '../lmm/objects/ObjectUtils'
  9. import { Object2D } from '../lmm/objects/Object2D'
  10. import { Img2D } from '../lmm/objects/Img2D'
  11. import { Text2D } from '../lmm/objects/Text2D'
  12. // 获取父级属性
  13. defineProps({
  14. size: { type: Object, default: { width: 0, height: 0 } },
  15. })
  16. // 鼠标样式
  17. const cursor = ref('default')
  18. // 对应canvas 画布的Ref对象
  19. const canvasRef = ref<HTMLCanvasElement>()
  20. /* 场景 */
  21. const scene = new Scene()
  22. /* 相机轨道控制器 */
  23. const orbitControler = new OrbitControler(scene.camera)
  24. /* 图案控制器 */
  25. const transformControler = new TransformControler()
  26. scene.add(transformControler)
  27. const images: HTMLImageElement[] = []
  28. for (let i = 1; i < 3; i++) {
  29. const image = new Image()
  30. image.src = `https://yxyy-pandora.oss-cn-beijing.aliyuncs.com/stamp-images/${i}.png`
  31. images.push(image)
  32. }
  33. const imagePromises = ImagePromises(images)
  34. /* 鼠标滑上的图案 */
  35. let imgHover: Object2D | null
  36. /* 选择图案的方法 */
  37. const selectObj = SelectObj(scene)
  38. /* 图形集合 */
  39. const group = new Group()
  40. scene.add(group)
  41. /* 文字内容 */
  42. const message = ref('Sphinx')
  43. /* 文字 */
  44. const text2D = new Text2D({
  45. text: message.value,
  46. position: new Vector2(300, 100),
  47. maxWidth: 400,
  48. style: {
  49. fontSize: 100,
  50. fillStyle: '#00acec',
  51. textAlign: 'right',
  52. textBaseline: 'top',
  53. },
  54. })
  55. group.add(text2D)
  56. function textChange() {
  57. text2D.text = message.value
  58. transformControler.updateFrame()
  59. scene.render()
  60. }
  61. /* 所以图片加载完成 */
  62. function onAllImageLoaded() {
  63. /* 添加图像 */
  64. group.add(
  65. ...images.map((image, i) => {
  66. const size = new Vector2(image.width, image.height).multiplyScalar(0.3)
  67. return new Img2D({
  68. image,
  69. position: new Vector2(0, i * 150 - 250),
  70. offset: new Vector2(-size.x / 2, -size.y / 2),
  71. rotate: 0.3,
  72. size,
  73. name: 'img-' + i,
  74. style: {
  75. shadowColor: 'rgba(0,0,0,0.5)',
  76. shadowBlur: 5,
  77. shadowOffsetY: 20,
  78. },
  79. })
  80. })
  81. )
  82. /* 渲染 */
  83. scene.render()
  84. }
  85. /* 按需渲染 */
  86. orbitControler.addEventListener('change', () => {
  87. scene.render()
  88. })
  89. transformControler.addEventListener('change', () => {
  90. scene.render()
  91. })
  92. /* 鼠标按下*/
  93. function pointerdown(event: PointerEvent) {
  94. const { button, clientX, clientY } = event
  95. const mp = scene.clientToClip(clientX, clientY)
  96. switch (button) {
  97. case 0:
  98. imgHover = selectObj(group.children, mp)
  99. transformControler.pointerdown(imgHover, mp)
  100. updateMouseCursor()
  101. break
  102. case 1:
  103. orbitControler.pointerdown(clientX, clientY)
  104. break
  105. }
  106. }
  107. /* 鼠标移动 */
  108. function pointermove(event: PointerEvent) {
  109. const { clientX, clientY } = event
  110. const mp = scene.clientToClip(clientX, clientY)
  111. orbitControler.pointermove(clientX, clientY)
  112. transformControler.pointermove(mp)
  113. imgHover = selectObj(group.children, mp)
  114. updateMouseCursor()
  115. }
  116. /* 滑动滚轮缩放 */
  117. function wheel({ deltaY }: WheelEvent) {
  118. orbitControler.doScale(deltaY)
  119. }
  120. /* 鼠标抬起 */
  121. window.addEventListener('pointerup', (event: PointerEvent) => {
  122. switch (event.button) {
  123. case 0:
  124. transformControler.pointerup()
  125. break
  126. case 1:
  127. orbitControler.pointerup()
  128. break
  129. }
  130. })
  131. /* 键盘按下 */
  132. window.addEventListener(
  133. 'keydown',
  134. ({ key, altKey, shiftKey }: KeyboardEvent) => {
  135. transformControler.keydown(key, altKey, shiftKey)
  136. updateMouseCursor()
  137. }
  138. )
  139. /* 键盘抬起 */
  140. window.addEventListener('keyup', ({ altKey, shiftKey }: KeyboardEvent) => {
  141. transformControler.keyup(altKey, shiftKey)
  142. })
  143. /* 更新鼠标样式 */
  144. function updateMouseCursor() {
  145. if (transformControler.mouseState) {
  146. cursor.value = 'none'
  147. } else if (imgHover) {
  148. cursor.value = 'pointer'
  149. } else {
  150. cursor.value = 'default'
  151. }
  152. }
  153. onMounted(() => {
  154. const canvas = canvasRef.value
  155. if (canvas) {
  156. scene.setOption({ canvas })
  157. Promise.all(imagePromises).then(onAllImageLoaded)
  158. }
  159. })
  160. </script>
  161. <template>
  162. <canvas
  163. ref="canvasRef"
  164. :style="{ cursor }"
  165. :width="size.width"
  166. :height="size.height"
  167. @pointerdown="pointerdown"
  168. @pointermove="pointermove"
  169. @wheel="wheel"
  170. ></canvas>
  171. <div id="text">
  172. <label>文字内容:</label>
  173. <input type="text" v-model="message" @input="textChange" />
  174. </div>
  175. </template>
  176. <style scoped>
  177. #text {
  178. position: absolute;
  179. left: 15px;
  180. top: 15px;
  181. }
  182. </style>