import {CADElementTS, CADElement} from '../core/element' import {SVGURI} from '../constant/Element' import {ProcessingTS} from './processing/index' export type Screen = {x: number, y: number} interface RendererProps { layer: HTMLElement, width?: number, height?: number, processing: ProcessingTS } class Renderer { svg: SVGSVGElement g: SVGGElement layer: HTMLElement elements: Array processing: ProcessingTS props: { left: number; top: number; width: number; height: number, multiple: number, scale: number } realWidth: number realHeight: number constructor({layer, width = layer.offsetWidth, height = layer.offsetHeight, processing}: RendererProps) { CADElement.init(this) this.props = {left: 0, top: 0, width, height, multiple: 1, scale: 1} this.elements = [] this.processing = processing this.init(layer) } private clickHandle = () => { this.elements.forEach(e => e.changeSelect(false)) } private init(layer) { this.svg = document.createElementNS(SVGURI, 'svg') this.g = document.createElementNS(SVGURI, 'g') this.svg.appendChild(this.g) this.layer = layer this.layer.style.position = 'relative' this.svg.style.position = 'absolute' this.svg.style.left = '0' this.svg.style.top = '0' this.svg.style.right = '0' this.svg.style.bottom = '0' this.svg.setAttribute('version', '1.0') this.svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg') this.svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink') this.svg.addEventListener('click', this.clickHandle, false) this.layer.appendChild(this.svg) } adaptLayer(width = this.layer.offsetWidth, height = this.layer.offsetHeight) { let centerStepX = this.props.width / 2 - this.props.left let centerStepY = this.props.height / 2 - this.props.top this.g.setAttribute('transform', ` translate(${this.props.left},${this.props.top}) translate(${centerStepX},${centerStepY}) scale(${this.props.scale},${this.props.scale}) translate(${-centerStepX},${-centerStepY}) `) this.svg.setAttribute('width', width.toString()) this.svg.setAttribute('height', height.toString()) this.svg.setAttribute('viewBox', `0 0 ${this.props.width} ${this.props.height}`) this.realWidth = width this.realHeight = height CADElement.update(this) } render() { CADElement.update(this) } // dom坐标转换为真实坐标 screenToRealPoint({x, y}: Screen) { let centerStepX = this.props.width / 2 - this.props.left let centerStepY = this.props.height / 2 - this.props.top let width = this.props.width / this.props.multiple let height = this.props.height / this.props.multiple if(width == 0 || height == 0){ return{ x:centerStepX, y:centerStepY }; } else{ return { x: ((x * this.props.width) / width - this.props.left - centerStepX) / this.props.scale + centerStepX, y: ((y * this.props.height) / height - this.props.top - centerStepY) / this.props.scale + centerStepY } } } // 点坐标转换真实坐标 realPointToScreen({x, y}: Screen) { let centerStepX = this.props.width / 2 - this.props.left let centerStepY = this.props.height / 2 - this.props.top let width = this.props.width / this.props.multiple let height = this.props.height / this.props.multiple return { x: ((x - centerStepX) * this.props.scale + centerStepX + this.props.left) * width / this.props.width, y: ((y - centerStepY) * this.props.scale + centerStepY + this.props.top) * height / this.props.height } } push (...elements: Array) { elements.forEach(element => { let prevEle = this.elements.find(ele => ele.zIndex > element.zIndex) if (prevEle) { try { this.g.insertBefore(element.real, prevEle.real) } catch(e) { this.g.appendChild(element.real) } this.elements.splice(this.elements.indexOf(prevEle), 0, element) } else { this.g.appendChild(element.real) this.elements.push(element) } }) } remove (...elements: Array) { elements.forEach(element => { try { this.g.removeChild(element.real) } catch(e) { } ~this.elements.indexOf(element) && this.elements.splice(this.elements.indexOf(element), 1) }) } destroy() { this.svg.removeEventListener('click', this.clickHandle, false) this.layer.removeChild(this.svg) } } export default Renderer