renderer.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import {CADElementTS, CADElement} from '../core/element'
  2. import {SVGURI} from '../constant/Element'
  3. import {ProcessingTS} from './processing/index'
  4. export type Screen = {x: number, y: number}
  5. interface RendererProps {
  6. layer: HTMLElement,
  7. width?: number,
  8. height?: number,
  9. processing: ProcessingTS
  10. }
  11. class Renderer {
  12. svg: SVGSVGElement
  13. g: SVGGElement
  14. layer: HTMLElement
  15. elements: Array<CADElementTS>
  16. processing: ProcessingTS
  17. props: {
  18. left: number;
  19. top: number;
  20. width: number;
  21. height: number,
  22. multiple: number,
  23. scale: number
  24. }
  25. realWidth: number
  26. realHeight: number
  27. constructor({layer, width = layer.offsetWidth, height = layer.offsetHeight, processing}: RendererProps) {
  28. CADElement.init(this)
  29. this.props = {left: 0, top: 0, width, height, multiple: 1, scale: 1}
  30. this.elements = []
  31. this.processing = processing
  32. this.init(layer)
  33. }
  34. private clickHandle = () => {
  35. this.elements.forEach(e => e.changeSelect(false))
  36. }
  37. private init(layer) {
  38. this.svg = document.createElementNS(SVGURI, 'svg')
  39. this.g = document.createElementNS(SVGURI, 'g')
  40. this.svg.appendChild(this.g)
  41. this.layer = layer
  42. this.layer.style.position = 'relative'
  43. this.svg.style.position = 'absolute'
  44. this.svg.style.left = '0'
  45. this.svg.style.top = '0'
  46. this.svg.style.right = '0'
  47. this.svg.style.bottom = '0'
  48. this.svg.setAttribute('version', '1.0')
  49. this.svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg')
  50. this.svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink')
  51. this.svg.addEventListener('click', this.clickHandle, false)
  52. this.layer.appendChild(this.svg)
  53. }
  54. adaptLayer(width = this.layer.offsetWidth, height = this.layer.offsetHeight) {
  55. let centerStepX = this.props.width / 2 - this.props.left
  56. let centerStepY = this.props.height / 2 - this.props.top
  57. this.g.setAttribute('transform', `
  58. translate(${this.props.left},${this.props.top})
  59. translate(${centerStepX},${centerStepY})
  60. scale(${this.props.scale},${this.props.scale})
  61. translate(${-centerStepX},${-centerStepY})
  62. `)
  63. this.svg.setAttribute('width', width.toString())
  64. this.svg.setAttribute('height', height.toString())
  65. this.svg.setAttribute('viewBox', `0 0 ${this.props.width} ${this.props.height}`)
  66. this.realWidth = width
  67. this.realHeight = height
  68. CADElement.update(this)
  69. }
  70. render() {
  71. CADElement.update(this)
  72. }
  73. // dom坐标转换为真实坐标
  74. screenToRealPoint({x, y}: Screen) {
  75. let centerStepX = this.props.width / 2 - this.props.left
  76. let centerStepY = this.props.height / 2 - this.props.top
  77. let width = this.props.width / this.props.multiple
  78. let height = this.props.height / this.props.multiple
  79. if(width == 0 || height == 0){
  80. return{
  81. x:centerStepX,
  82. y:centerStepY
  83. };
  84. }
  85. else{
  86. return {
  87. x: ((x * this.props.width) / width - this.props.left - centerStepX) / this.props.scale + centerStepX,
  88. y: ((y * this.props.height) / height - this.props.top - centerStepY) / this.props.scale + centerStepY
  89. }
  90. }
  91. }
  92. // 点坐标转换真实坐标
  93. realPointToScreen({x, y}: Screen) {
  94. let centerStepX = this.props.width / 2 - this.props.left
  95. let centerStepY = this.props.height / 2 - this.props.top
  96. let width = this.props.width / this.props.multiple
  97. let height = this.props.height / this.props.multiple
  98. return {
  99. x: ((x - centerStepX) * this.props.scale + centerStepX + this.props.left) * width / this.props.width,
  100. y: ((y - centerStepY) * this.props.scale + centerStepY + this.props.top) * height / this.props.height
  101. }
  102. }
  103. push (...elements: Array<CADElementTS>) {
  104. elements.forEach(element => {
  105. let prevEle = this.elements.find(ele => ele.zIndex > element.zIndex)
  106. if (prevEle) {
  107. try {
  108. this.g.insertBefore(element.real, prevEle.real)
  109. } catch(e) {
  110. this.g.appendChild(element.real)
  111. }
  112. this.elements.splice(this.elements.indexOf(prevEle), 0, element)
  113. } else {
  114. this.g.appendChild(element.real)
  115. this.elements.push(element)
  116. }
  117. })
  118. }
  119. remove (...elements: Array<CADElementTS>) {
  120. elements.forEach(element => {
  121. try {
  122. this.g.removeChild(element.real)
  123. } catch(e) {
  124. }
  125. ~this.elements.indexOf(element) && this.elements.splice(this.elements.indexOf(element), 1)
  126. })
  127. }
  128. destroy() {
  129. this.svg.removeEventListener('click', this.clickHandle, false)
  130. this.layer.removeChild(this.svg)
  131. }
  132. }
  133. export default Renderer