viewer.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import { Transform } from "konva/lib/Util";
  2. import mitt from 'mitt'
  3. import { alignPortMat, Pos } from "./math";
  4. import { MathUtils } from "three";
  5. export type ViewerProps = {
  6. size?: number[];
  7. bound?: number[];
  8. padding: number | number[];
  9. retain: boolean;
  10. };
  11. export class Viewer {
  12. props: ViewerProps;
  13. viewMat: Transform;
  14. partMat: Transform = new Transform();
  15. bus = mitt<{ transformChange: Transform }>()
  16. constructor(props: Partial<ViewerProps> = {}) {
  17. this.props = {
  18. padding: 0,
  19. retain: true,
  20. ...props,
  21. }
  22. this.viewMat = new Transform();
  23. }
  24. get bound() {
  25. return this.props.bound
  26. }
  27. setBound(bound: number[], size?: number[], padding?: number | number[], retain?: boolean) {
  28. this.props.bound = bound
  29. if (padding) {
  30. this.props.padding = padding
  31. }
  32. if (retain) {
  33. this.props.retain = retain
  34. }
  35. if (size) {
  36. this.props.size = size
  37. }
  38. padding = this.props.padding
  39. retain = this.props.retain
  40. size = this.props.size
  41. if (!size) {
  42. throw '缺少视窗size'
  43. }
  44. this.partMat = alignPortMat(
  45. [
  46. {x: bound[0], y: bound[1]},
  47. {x: bound[2], y: bound[3]},
  48. ],
  49. [
  50. {x: 0, y: 0},
  51. {x: size[0], y: size[1]},
  52. ],
  53. retain,
  54. typeof padding === "number"
  55. ? padding
  56. : {x: padding[0], y: padding[1]}
  57. );
  58. }
  59. move(position: Pos, initMat = this.viewMat) {
  60. this.mutMat(new Transform().translate(position.x, position.y), initMat);
  61. }
  62. movePixel(position: Pos, initMat = this.viewMat) {
  63. if (isNaN(position.x) || isNaN(position.y)) {
  64. console.error(`无效移动位置${position.x} ${position.y}`)
  65. return;
  66. }
  67. const offsetX = position.x
  68. const currentX = this.viewMat.decompose().x
  69. const finX = currentX + offsetX
  70. const x = finX - currentX
  71. const mat = initMat.copy().invert()
  72. const p1 = mat.point({x: 0, y: 0})
  73. const p2 = mat.point({x, y: position.y})
  74. this.move({x: p2.x - p1.x, y: p2.y - p1.y})
  75. // const info = initMat.decompose()
  76. // const tf = new Transform()
  77. // tf.rotate(info.rotation)
  78. // tf.scale(info.scaleX, info.scaleY)
  79. // this.move(tf.invert().point(position), this.viewMat)
  80. }
  81. scale(center: Pos, scale: Pos, initMat = this.viewMat) {
  82. const base = initMat.decompose().scaleX
  83. if (base * scale.x < 0.001 || base * scale.x > 1000) {
  84. console.error('缩放范围0.001~1000 已超过范围无法缩放')
  85. return;
  86. }
  87. if (isNaN(center.x) || isNaN(center.y)) {
  88. console.error(`无效中心点${center.x} ${center.y}`)
  89. return;
  90. }
  91. this.mutMat(
  92. new Transform()
  93. .translate(center.x, center.y)
  94. .multiply(
  95. new Transform()
  96. .scale(scale.x, scale.y)
  97. .multiply(new Transform().translate(-center.x, -center.y))
  98. ),
  99. initMat
  100. );
  101. }
  102. scalePixel(center: Pos, scale: Pos, initMat = this.viewMat) {
  103. const pos = initMat.copy().invert().point(center)
  104. this.scale(pos, scale, initMat)
  105. }
  106. rotate(center: Pos, angleRad: number, initMat = this.viewMat) {
  107. this.mutMat(
  108. new Transform()
  109. .translate(center.x, center.y)
  110. .multiply(
  111. new Transform()
  112. .rotate(angleRad)
  113. .multiply(new Transform().translate(-center.x, -center.y))
  114. ),
  115. initMat
  116. );
  117. }
  118. rotatePixel(center: Pos, angleRad: number, initMat = this.viewMat) {
  119. const pos = initMat.copy().invert().point(center)
  120. this.rotate(pos, angleRad, initMat)
  121. }
  122. mutMat(mat: Transform, initMat = this.viewMat) {
  123. // this.setViewMat(mat.copy().multiply(initMat))
  124. this.setViewMat(initMat.copy().multiply(mat))
  125. }
  126. setViewMat(mat: number[] | Transform) {
  127. if (mat instanceof Transform) {
  128. this.viewMat = mat.copy();
  129. } else {
  130. this.viewMat = new Transform(mat)
  131. }
  132. let dec = this.viewMat.decompose()
  133. if (dec.x > 10) {
  134. dec.x = 10
  135. this.viewMat = new Transform()
  136. .translate(dec.x, dec.y)
  137. .scale(dec.scaleX, dec.scaleY)
  138. .rotate(MathUtils.degToRad(dec.rotation))
  139. }
  140. // while(dec.x > 0.01) {
  141. // console.log(dec.x)
  142. // this.viewMat = this.viewMat.copy().translate(-dec.x, 0)
  143. // dec = this.viewMat.decompose()
  144. // }
  145. this.bus.emit('transformChange', this.transform)
  146. }
  147. get transform() {
  148. return this.partMat.copy().multiply(this.viewMat);
  149. }
  150. get current() {
  151. return this.viewMat.decompose()
  152. }
  153. }