// 发布订阅,事件模型 var Event = (function () { var _default = 'default'; var _shift = Array.prototype.shift; var _unshift = Array.prototype.unshift; function createEvent() { var namespaceCache = {} function _listen(cache, key, fn) { if (cache[key]) { cache[key].push(fn) } else { cache[key] = [fn] } } function _trigger() { var args = arguments return new Promise(function (resolve) { setTimeout(function () { var cache = _shift.call(args); var key = _shift.call(args); var stack = cache[key] if (!stack || stack.length === 0) return; stack.forEach(function (fn) { fn.apply(this, args) }) resolve(stack); }, 100) }) } function _remove(cache, key, fn) { var stack = cache[key] if (!stack || stack.length === 0) return if (fn) { for (var i = stack.length; i >= 0; i--) { if (stack[i] === fn) { stack.splice(i, 1) } } } else { stack.length = 0 } } function _create(namespace) { namespace = namespace || _default if (namespaceCache[namespace]) { return namespaceCache[namespace] } var cache = {} var ret = { listen: function (key, fn) { _listen(cache, key, fn) }, once: function (key, fn) { fn.__once = true _listen(cache, key, fn) }, remove: function (key, fn) { _remove(cache, key, fn) }, trigger: function () { _unshift.call(arguments, cache) _trigger.apply(this, arguments).then(function (stack) { if (stack) { for (var i = stack.length; i >= 0; i--) { if (stack[i] && stack[i].__once) { stack.splice(i, 1) } } } }) } } namespaceCache[namespace] = ret; return ret } return { create: _create, once: function () { this.create().once.apply(this, arguments) }, listen: function () { this.create().listen.apply(this, arguments) }, remove: function () { this.create().remove.apply(this, arguments) }, trigger: function () { this.create().trigger.apply(this, arguments) } } } return createEvent() })(); var grendCAD = (function grentWall() { var util = { /** * 计算直线向量 * @param {*} line */ lineVector(line) { var cpoint = { x: line.points[1].x - line.points[0].x, y: line.points[1].y - line.points[0].y } var xd = Math.abs(Math.floor(cpoint.x / 1)) var yd = Math.abs(Math.floor(cpoint.y / 1)) var js = xd > yd ? xd : yd var verctor = { x: cpoint.x / js, y: cpoint.y / js, } return verctor }, /** * 计算直线与X轴夹角 * @param {*} line1 */ lineAngle(line1) { var height = line1[0].y - line1[1].y, width = line1[0].x - line1[1].x; if (width == 0) { // 如果和y轴平行,角度为90或270 return line1[0].y >= line1[1].y ? 90 : 270; } else { var tan = Math.atan(height / width), angle = tan * 180 / Math.PI; return tan > 0 ? (line1[0].x > line1[1].x ? angle : angle + 180) : (line1[0].x > line1[1].x ? angle + 360 : angle + 180); } }, /** * 计算直线的长度 * @param {*} line */ lineDistance(line) { return Math.sqrt(Math.pow(line[0].x - line[1].x, 2) + Math.pow(line[0].y - line[1].y, 2)) }, isInfinity(num) { return num === Infinity || num === -Infinity }, /** * 获取一组坐标的XY坐标区间 * @param {*} points */ getSection(points) { var ret = { minx: points[0].x, maxx: points[0].x, miny: points[0].y, maxy: points[0].y } points.forEach(function (point) { if (ret.minx > point.x) { ret.minx = point.x } if (ret.maxx < point.x) { ret.maxx = point.x } if (ret.miny > point.y) { ret.miny = point.y } if (ret.maxy < point.y) { ret.maxy = point.y } }) return ret }, /** * 计算垂直向量 * @param {向量} arr */ verticalLine(line) { var arr = [ line.points[1].x - line.points[0].x, line.points[1].y - line.points[0].y ] if (arr.length !== 0) { var x, y; y = Math.sqrt(1 / ((arr[1] * arr[1]) / (arr[0] * arr[0]) + 1)); x = Math.sqrt(1 - y * y); return [x, y]; } return []; }, /** * 将所有坐标转化为指定范围之间的值,但是保持比例不变 * @param {*} points 要转化的坐标 * @param {*} section 指定范围 * @returns Array 转化后的值 */ tranProp(points, section) { var args = util.getSection(points) var xlen = args.maxx - args.minx var ylen = args.maxy - args.miny var prop = xlen > ylen ? xlen : ylen var offsetX = -(args.minx + xlen / 2) var offsetY = -(args.miny + ylen / 2) var range = section[1] - section[0] return { offset: { x: offsetX, y: offsetY }, prop, range: range } }, /** * 将屏幕转化为真实坐标 * @param {*} point * @param {*} section */ tranPoint(point, section) { return { x: point.x + section.minx, y: point.y + section.miny } }, /** * 判断点是否在线上 * @param {*} point 要判断的点 * @param {*} line 线段 * @param {*} width 线宽 */ isContainPoint(point, line, width) { var dis = 0 var s1 = line[1].x - line[0].x var s2 = point.x - line[0].x var s3 = point.x - line[1].x var k1 = line[1].y - line[0].y var k2 = point.y - line[0].y var k3 = point.y - line[1].y var max = width / 2 var min = 0 - max var cross = s1 * s2 + k1 * k2; var d2 = s1 * s1 + k1 * k1; if (cross <= 0) { dis = Math.sqrt(s2 * s2 + k2 * k2); } else if (cross >= d2) { dis = Math.sqrt(s3 * s3 + k3 * k3); } else { var r = cross / d2; var px = line[0].x + s1 * r; var py = line[0].y + k1 * r; dis = Math.sqrt((point.x - px) * (point.x - px) + (py - point.y) * (py - point.y)); } return dis >= min && dis <= max }, /** * 判断两条线段是否相交 * @param {*} line1 * @param {*} line2 */ isLineIntersect(line1, line2) { var a1 = line1[1].y - line1[0].y; var b1 = line1[0].x - line1[1].x; var c1 = a1 * line1[0].x + b1 * line1[0].y; //转换成一般式: Ax+By = C var a2 = line2[1].y - line2[0].y; var b2 = line2[0].x - line2[1].x; var c2 = a2 * line2[0].x + b2 * line2[0].y; // 计算交点 var d = a1 * b2 - a2 * b1; // 当d==0时,两线平行 if (d == 0) { return false; } else { var x = (b2 * c1 - b1 * c2) / d; var y = (a1 * c2 - a2 * c1) / d; // 检测交点是否在两条线段上 if ((isInBetween(line1[0].x, x, line1[1].x) || isInBetween(line1[0].y, y, line1[1].y)) && (isInBetween(line2[0].x, x, line2[1].x) || isInBetween(line2[0].y, y, line2[1].y))) { return true; } } function isInBetween(a, b, c) { // 如果b几乎等于a或c,返回false.为了避免浮点运行时两值几乎相等,但存在相差0.00000...0001的这种情况出现使用下面方式进行避免 if (Math.abs(a - b) < 0.000001 || Math.abs(b - c) < 0.000001) { return false; } return (a <= b && b <= c) || (c <= b && b <= a); } return false; }, /** * 判断两个点是否相同 * @param {*} point1 * @param {*} poin2 */ equalPoint(point1, poin2) { return point1.x === poin2.x && point1.y === poin2.y }, /** * 判断两个面是否相交, * @param {*} face1 * @param {*} face2 */ isFaceIntersect(face1, face2) { for (var i = 0; i < face1.length; i++) { var next = i + 1 === face1.length ? 0 : i + 1 var line1 = [face1[i], face1[next]] for (var j = 0; j < face2.length; j++) { var next = j + 1 === face2.length ? 0 : j + 1 var line2 = [face2[j], face2[next]] var isIntersect1 = util.isLineIntersect(line2, line1) var isIntersect2 = util.isLineIntersect(line1, line2) if (isIntersect1 && isIntersect2) { return true } } } }, /** * 判断一个点是否在面上 * @param {*} face1 * @param {*} face2 */ pointInside(point, face) { var inside = false; var x = point.x, y = point.y; for (var i = 0, j = face.length - 1; i < face.length; j = i++) { var xi = face[i].x, yi = face[i].y; var xj = face[j].x, yj = face[j].y; if (((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi)) { inside = !inside; } } return inside; } } /** * 获取一个元素在指定父元素或文档中的位置 */ function getPosition(dom, parent) { var ret = { x: 0, y: 0 } while (dom && dom !== parent && dom !== document.documentElement) { ret.x += dom.offsetLeft ret.y += dom.offsetTop dom = dom.offsetParent } return ret } /** * 添加拖拽事件 */ function addMouseEvent(dom, event) { dom.addEventListener('mousedown', function downHandle(ev) { var prevPoint = { x: ev.pageX, y: ev.pageY } var con = event.down(prevPoint) if (!con) return; document.documentElement.addEventListener('mousemove', moveHandle, { passive: false }) document.documentElement.addEventListener('mouseup', endHandle, { passive: false }) function moveHandle(ev) { event.move({ x: ev.pageX, y: ev.pageY }, prevPoint) prevPoint = { x: ev.pageX, y: ev.pageY } } function endHandle(ev) { document.documentElement.removeEventListener('mousemove', moveHandle, { passive: false }) document.documentElement.removeEventListener('mouseup', endHandle, { passive: false }) event.up() } }, false) } /** * 包含对象 */ function inherit(origin, target) { for (var key in target) { origin.prototype[key] = target[key] } } /** * 墙面跟相机 */ var Wall = (function Wall() { /** * 获取面的所有点 * @param {*} face */ function getFacePoints(face) { var start = face[0] var ret = [] var iteration = start do { ret.push(iteration.points[0]) iteration = face.find(function (item) { return item.id === iteration.linkedLineID[1] }) } while (start !== iteration) return ret } function Wall(data, cameras) { this.lineWidth = 8 this.cameras = cameras this.stateStack = [] var faces = {} data.forEach(function (line) { if (faces[line.roomIndex]) { faces[line.roomIndex].push(line) } else { faces[line.roomIndex] = [line] } }) this.faces = faces // this.regEvent() // this.init() // this.draw() } Wall.prototype._down = function (point, renderer) { this.preservationState() for (var key in this.faces) { var face = this.faces[key] for (var i = 0, line; line = face[i]; i++) { if (util.isContainPoint(point, line.points, (this.lineWidth + 4) / renderer.status.prop)) { return { face: face, line: line, dire: util.verticalLine(line) } } } } } Wall.prototype.updateLine = function (line, x, y) { if (!x && !y) return; var face for (var key in this.faces) { var index = this.faces[key].findIndex(function (item) { return item === line }) if (~index) { face = this.faces[key] break } } if (!face) return var prevLine = face.find(function (cLine) { return line.linkedLineID[0] === cLine.id }) var lastLine = face.find(function (cLine) { return line.linkedLineID[1] === cLine.id }) var prevK = (prevLine.points[1].y - prevLine.points[0].y) / (prevLine.points[1].x - prevLine.points[0].x) var lastK = (lastLine.points[1].y - lastLine.points[0].y) / (lastLine.points[1].x - lastLine.points[0].x) var prevX, prevY, lastX, lastY if (x) { prevX = prevLine.points[1].x + x prevY = (prevX - prevLine.points[0].x) * prevK + prevLine.points[0].y lastX = lastLine.points[0].x + x lastY = (lastX - lastLine.points[0].x) * lastK + lastLine.points[0].y } else { prevY = prevLine.points[1].y + y prevX = (prevY - prevLine.points[0].y) / prevK + prevLine.points[0].x lastY = lastLine.points[0].y + y lastX = (lastY - lastLine.points[0].y) / lastK + lastLine.points[0].x } if (util.isInfinity(prevX) || util.isInfinity(prevY) || util.isInfinity(lastX) || util.isInfinity(lastY)) { prevX = prevLine.points[1].x + x prevY = prevLine.points[1].y + y lastX = lastLine.points[0].x + x lastY = lastLine.points[0].y + y } prevLine.points[1].x = prevX prevLine.points[1].y = prevY lastLine.points[0].x = lastX lastLine.points[0].y = lastY line.points[0].x = prevLine.points[1].x line.points[0].y = prevLine.points[1].y line.points[1].x = lastLine.points[0].x line.points[1].y = lastLine.points[0].y } Wall.prototype._move = function (point, prevPoint, movePosition, renderer) { var xdis = point.x - prevPoint.x var ydis = point.y - prevPoint.y var revoke = false var dire = movePosition.dire[0] - movePosition.dire[1] > 0 ? 'X' : 'Y' if (dire === 'X') { this.updateLine(movePosition.line, xdis, 0) } else { this.updateLine(movePosition.line, 0, ydis) } var activeFacePoint = getFacePoints(movePosition.face) for (let key in this.faces) { if (this.faces[key] !== movePosition.face && util.isFaceIntersect(activeFacePoint, getFacePoints(this.faces[key]))) { revoke = true; break; } } var cameras; if (this.cameras && (cameras = this.cameras[movePosition.face[0].roomIndex])) { for (var i = 0, camera; camera = cameras[i]; i++) { if (!util.pointInside(camera, activeFacePoint)) { revoke = true break; } } } if (revoke) { if (dire === 'X') { this.updateLine(movePosition.line, -xdis, 0) } else { this.updateLine(movePosition.line, 0, -ydis) } } else { this.trigger('changePosition', movePosition.line) renderer.render() } } Wall.prototype.draw = function (renderer, context) { for (var key in this.faces) { var face = this.faces[key] for (var i = 0, line; line = face[i]; i++) { var _line = [ renderer.transScreenPoint(line.points[0]), renderer.transScreenPoint(line.points[1]) ] context.beginPath(); context.strokeStyle = line.selected ? 'rgb(255,85,0)' : '#fff'; context.lineWidth = this.lineWidth; context.lineCap = 'round' context.moveTo(_line[0].x, _line[0].y); context.lineTo(_line[1].x, _line[1].y); context.closePath(); context.stroke(); } } if (this.cameras) { for (var key in this.cameras) { for (var i = 0; i < this.cameras[key].length; i++) { var point = renderer.transScreenPoint(this.cameras[key][i]) context.fillStyle = "#00cc00"; context.fillRect(point.x - this.lineWidth / 2, point.y - this.lineWidth / 2, this.lineWidth, this.lineWidth); } } } } Wall.prototype.preservationState = function (renderer) { var state = {} for (var key in this.faces) { state[key] = {} for (var i = 0; i < this.faces[key].length; i++) { var line = this.faces[key][i] state[key][line.id] = [{ x: line.points[0].x, y: line.points[0].y }, { x: line.points[1].x, y: line.points[1].y } ] } } this.stateStack.push(state) } Wall.prototype.revokeState = function (renderer) { var state = this.stateStack.pop() for (var key in state) { for (var id in state[key]) { var cline = state[key][id] var line = this.faces[key].find(function (line) { return line.id === id }) line.points[0].x = cline[0].x line.points[0].y = cline[0].y line.points[1].x = cline[1].x line.points[1].y = cline[1].y } } renderer.render(); } Wall.prototype.getIndex = function() { return -1 } inherit(Wall, Event.create('__wall__')) return Wall })(); /** * 当前所在位置 */ var Position = (function Position() { function Position(point, angle) { this.point = point this.angle = angle this.withinW = 8 this.abroadW = 4 this.lightW = 14 this.lightrRdian = 1 / 2.5 * Math.PI } Position.prototype.draw = function (renderer, context) { var point = renderer.transScreenPoint(this.point) var startRdian = this.angle - this.lightrRdian / 2 var endRdian = this.angle + this.lightrRdian / 2 var ligWidth = this.withinW + this.abroadW + this.lightW var abroadWidth = this.withinW + this.abroadW var grd = context.createRadialGradient(point.x, point.y, abroadWidth, point.x, point.y, ligWidth); grd.addColorStop(0, "rgba(0,200,175,0.9)"); grd.addColorStop(1, "rgba(0,200,175,0.3)"); context.beginPath(); context.fillStyle = grd; context.moveTo(point.x, point.y); context.arc(point.x, point.y, ligWidth, startRdian, endRdian, false); context.fill() context.closePath(); context.beginPath(); context.fillStyle = "#ffffff"; context.arc(point.x, point.y, abroadWidth, 0, 2 * Math.PI, false); context.fill() context.closePath(); context.beginPath(); context.fillStyle = "rgba(0,200,175,1)"; context.arc(point.x, point.y, this.withinW, 0, 2 * Math.PI, false); context.fill() context.closePath(); } inherit(Position, Event.create('__position__')) return Position })(); /** * 门(第一个版本) */ (function Door() { function Door(line, point) { this.line = line this.point = point this.lineWidth = 8 this.color = 'rgba(0,200,175,1)' } Door.prototype.getPoints = function () { var cpoint = util.lineVector(this.line) var vpoint = util.verticalLine(this.line) var width = 3 var point1 = { x: this.point.x + cpoint.x * width, y: this.point.y + cpoint.y * width } var point2 = { x: this.point.x + vpoint[0] * width, y: this.point.y + vpoint[1] * width } return [this.point, point1, point2] } Door.prototype.draw = function (renderer, context) { points = this.getPoints().map(function (point) { return renderer.transScreenPoint(point) }) var startDeg = util.lineAngle([points[1], points[0]]) * Math.PI / 180 var endDeg = util.lineAngle([points[2], points[0]]) * Math.PI / 180 var deg = endDeg - startDeg var router = ((deg > Math.PI || (deg < 0 && deg > -Math.PI)) ? true : false) var r = util.lineDistance([points[1], points[0]]) var grd = context.createLinearGradient(points[0].x, points[0].y, points[0].x, points[0].y - 100); grd.addColorStop(0, "rgba(25,31,31,1)"); grd.addColorStop(0.3, "rgba(255,255,255,1)"); grd.addColorStop(0.7, "rgba(255,255,255,1)"); grd.addColorStop(0.71, "rgba(25,31,31,1)"); context.strokeStyle = this.color; context.lineWidth = this.lineWidth; context.beginPath(); context.moveTo(points[0].x, points[0].y); context.arc(points[0].x, points[0].y, r, startDeg, endDeg, router); context.lineTo(points[0].x, points[0].y); context.stroke() context.closePath(); context.beginPath(); context.strokeStyle = '#000'; context.moveTo(points[0].x, points[0].y); context.lineTo(points[1].x, points[1].y); context.stroke() context.closePath(); } return Door }); /** * 门,正式版本 */ var Door = (function Door() { var count = 0 function Door(line, points) { count++ this.line = line this.points = points this.lineWidth = 8 this.color = 'rgba(0,200,175,1)' } Door.prototype.getIndex = function() { return 1; } Door.prototype.detection = function () { var collision = true var detection = [] this.line.doors && detection.push.apply(detection, this.line.doors) this.line.casements && detection.push.apply(detection, this.line.casements) for (var i = 0; i < detection.length; i++) { if (detection[i].points !== this.points && ( util.isContainPoint(this.points[0], detection[i].points, 0.1) || util.isContainPoint(this.points[1], detection[i].points, 0.1) )) { collision = false } } return collision && util.isContainPoint(this.points[0], this.line.points, 0.1) && util.isContainPoint(this.points[1], this.line.points, 0.1) } Door.prototype._down = function (point) { var info = { vector: util.lineVector(this.line) }; if (util.lineDistance([point, this.points[0]]) < 0.3) { info.scalePoint = 0 } else if (util.lineDistance([point, this.points[1]]) < 0.3) { info.scalePoint = 1 } else if (!util.isContainPoint(point, this.points, 0.5)) { info = null } return info } Door.prototype.getMoveChange = function (vector, curr, prev) { var move = { x: vector.x < 0 ? (prev.x - curr.x) : (curr.x - prev.x), y: vector.y < 0 ? (prev.y - curr.y) : (curr.y - prev.y) } if (Math.abs(vector.x) > Math.abs(vector.y)) { move = { x: move.x * vector.x, y: move.x * vector.y } } else { move = { x: move.y * vector.x, y: move.y * vector.y } } return move } Door.prototype._move = function (point, prevPoint, info, renderer) { if (info.scalePoint !== undefined) { this.scale(point, prevPoint, info, renderer) } else { this.move(point, prevPoint, info.vector, renderer) } } Door.prototype.move = function (point, prevPoint, vector, renderer) { var move = this.getMoveChange(vector, point, prevPoint) this.points.forEach(function (point) { point.x += move.x point.y += move.y }) if (this.detection()) { renderer.render() this.trigger('changePoints') } else { this.points.forEach(function (point) { point.x -= move.x point.y -= move.y }) } } Door.prototype.scale = function (point, prevPoint, info, renderer) { var move = this.getMoveChange(info.vector, point, prevPoint) this.points[info.scalePoint].x += move.x this.points[info.scalePoint].y += move.y if (this.detection()) { renderer.render() this.trigger('changePoints') } else { this.points[info.scalePoint].x -= move.x this.points[info.scalePoint].y -= move.y } } Door.prototype.draw = function (renderer, context) { var points = this.points.map(function (point) { return renderer.transScreenPoint(point) }) context.strokeStyle = this.color; context.lineWidth = this.lineWidth; context.beginPath(); context.moveTo(points[0].x, points[0].y); context.lineTo(points[1].x, points[1].y); context.stroke() context.closePath(); } inherit(Door, Event.create('__door' + count + '__')) return Door })(); /** * 窗 */ var Casement = (function Casement() { var count = 0 function Casement(line, points) { count++ this.line = line this.points = points this.lineWidth = 8 this.color = '#202123' } Casement.prototype.getIndex = function () { return 1; } Casement.prototype.detection = function () { var collision = true var detection = [] this.line.doors && detection.push.apply(detection, this.line.doors) this.line.casements && detection.push.apply(detection, this.line.casements) for (var i = 0; i < detection.length; i++) { if (detection[i].points !== this.points &&( util.isContainPoint(this.points[0], detection[i].points, 0.1) || util.isContainPoint(this.points[1], detection[i].points, 0.1) ) ) { collision = false } } return collision && util.isContainPoint(this.points[0], this.line.points, 0.1) && util.isContainPoint(this.points[1], this.line.points, 0.1) } Casement.prototype._down = function (point) { var info = { vector: util.lineVector(this.line) }; if (util.lineDistance([point, this.points[0]]) < 0.3) { info.scalePoint = 0 } else if (util.lineDistance([point, this.points[1]]) < 0.3) { info.scalePoint = 1 } else if (!util.isContainPoint(point, this.points, 0.5)) { info = null } return info } Casement.prototype.getMoveChange = function (vector, curr, prev) { var move = { x: vector.x < 0 ? (prev.x - curr.x) : (curr.x - prev.x), y: vector.y < 0 ? (prev.y - curr.y) : (curr.y - prev.y) } if (Math.abs(vector.x) > Math.abs(vector.y)) { move = { x: move.x * vector.x, y: move.x * vector.y } } else { move = { x: move.y * vector.x, y: move.y * vector.y } } return move } Casement.prototype._move = function (point, prevPoint, info, renderer) { if (info.scalePoint !== undefined) { this.scale(point, prevPoint, info, renderer) } else { this.move(point, prevPoint, info.vector, renderer) } } Casement.prototype.move = function (point, prevPoint, vector, renderer) { var move = this.getMoveChange(vector, point, prevPoint) this.points.forEach(function (point) { point.x += move.x point.y += move.y }) if (this.detection()) { renderer.render() this.trigger('changePoints') } else { this.points.forEach(function (point) { point.x -= move.x point.y -= move.y }) } } Casement.prototype.scale = function (point, prevPoint, info, renderer) { var move = this.getMoveChange(info.vector, point, prevPoint) this.points[info.scalePoint].x += move.x this.points[info.scalePoint].y += move.y if (this.detection()) { renderer.render() this.trigger('changePoints') } else { this.points[info.scalePoint].x -= move.x this.points[info.scalePoint].y -= move.y } } Casement.prototype.draw = function (renderer, context) { var points = this.points.map(function (point) { return renderer.transScreenPoint(point) }) context.strokeStyle = this.color; context.lineWidth = this.lineWidth; context.beginPath(); context.moveTo(points[0].x, points[0].y); context.lineTo(points[1].x, points[1].y); context.stroke() context.closePath(); } inherit(Casement, Event.create('__casement' + count + '__')) return Casement })(); /** * 总控制 */ var Renderer = (function Renderer() { var execFilter = 'FUNCTION_EXEC' /** * 渲染器 * @param {*} canvas 画布 * @param {*} wallData 墙面数据 */ function Renderer(canvas, wallData) { this.canvas = canvas this.context = canvas.getContext('2d') this.origin = wallData this.models = [] this.init() this.regEvent() } /** * 计算所有需要的信息,渲染器需要的宽高,真实比例等 */ Renderer.prototype.init = function () { this.width = this.canvas.width this.height = this.canvas.height this.wMultiple = this.canvas.width / this.canvas.offsetWidth this.hMultiple = this.canvas.height / this.canvas.offsetHeight this.context.translate(this.width / 2, this.height / 2); this.screenOffset = getPosition(this.canvas) var points = [] this.origin.forEach(function (line) { points = points.concat(...line.points) }) var result = util.tranProp(points, [-0.99, 0.99]) this.status = { offset: result.offset, prop: result.prop, range: result.range } } /** * 真实点位转化为画布点位 */ Renderer.prototype.transScreenPoint = function (point) { var spoint = { x: point.x, y: point.y } spoint.x += this.status.offset.x spoint.y += this.status.offset.y spoint.x = (spoint.x * this.status.range / this.status.prop) * (this.width / 2) spoint.y = (spoint.y * this.status.range / this.status.prop) * (this.height / 2) return spoint } /** * 画布点位转化为真实点位 */ Renderer.prototype.transRealPoint = function (point) { return { x: (point.x * this.status.prop) / (this.status.range * this.width / 2) - this.status.offset.x, y: (point.y * this.status.prop) / (this.status.range * this.height / 2) - this.status.offset.y } } Renderer.prototype.regEvent = function () { var sinfo, model; var section = { minx: -this.width / 2, maxx: this.width / 2, miny: -this.height / 2, maxy: this.height / 2 } var startPoint = null var prevPoint = null var event = { down(offset) { offset.x = (offset.x - this.screenOffset.x) * this.wMultiple offset.y = (offset.y - this.screenOffset.y) * this.hMultiple startPoint = this.transRealPoint(util.tranPoint(offset, section)) prevPoint = startPoint var models = Object.assign([], this.models).sort(function(a, b) { return ((b.getIndex && b.getIndex()) || 0) - ((a.getIndex && a.getIndex()) || 0) }) for (var i = 0; i < models.length; i++) { sinfo = models[i]._down && models[i]._down(startPoint, this) if (sinfo) { model = models[i] break; } } return sinfo }, move(move) { move.x = (move.x - this.screenOffset.x) * this.wMultiple move.y = (move.y - this.screenOffset.y) * this.hMultiple var point = this.transRealPoint(util.tranPoint(move, section)) model._move(point, prevPoint, sinfo, this, this.context) prevPoint = point }, up() { model._up && model._up(startPoint, prevPoint, this, this.context) startPoint = null prevPoint = null model = null sinfo = null } } event.down = event.down.bind(this) event.move = event.move.bind(this) event.up = event.up.bind(this) addMouseEvent(this.canvas, event) } /** * 统一执行命令 */ Renderer.prototype.unifiedExec = function () { var args = Array.from(arguments) var command = args.shift() var ret = [] var filter = args[args.length - 1] === execFilter this.models.map(function (model) { if (model[command]) { if (filter) { ret.push(args[0].apply(model, [model, args.slice(1, args.length - 1)])) } else { ret.push(model[command].apply(model, args)) } } else { ret.push(null) } }) return ret } /** * 保存状态 */ Renderer.prototype.preservationState = function () { this.unifiedExec('preservationState', this) } Renderer.prototype.revokeState = function () { this.unifiedExec('revokeState', this) } /** * 渲染所有依赖了渲染器的模型 */ Renderer.prototype.render = function () { var that = this that.context.clearRect(-that.width / 2, -that.height / 2, that.width, that.height) that.unifiedExec('draw', function (model) { that.context.save() model.draw(that, that.context) that.context.restore() }, execFilter); } return Renderer })(); function update3D(line) { if (line.updateLine3D) { line.updateLine3D() } else { console.error('当前线条没有注册3D线条方法') } } function update2d(wall, line) { var update = line.update line.update = function (dirs, len) { var args = [ {x: 0, y: 0}, {x: 0, y: 0}, { line: this, face: wall.faces[this.roomIndex] } ] args[0][dirs[0]] = len; wall._move.apply(wall, args.concat([dirs[1]])) update && update.bind(this)() } } return function (dom, line2Ds, cameras) { var doors = [] var casements = [] var wall = new Wall(line2Ds, cameras) line2Ds.forEach(function(line) { if (line.doors) { doors.push.apply(doors, line.doors.map(function(door) { return new Door(line, door.points) }) ) } if (line.casements) { casements.push.apply(casements, line.casements.map(function (casements) { return new Casement(line, casements.points) }) ) } update2d(wall, line) }) wall.listen('changePosition', function(line2D) { line2Ds.forEach(function (line) { if (line.id === line2D.linkedLineID[0] || line.id === line2D.linkedLineID[1]) { update3D(line) } }) update3D(line2D) }) doors.concat(casements).forEach(function (obj) { obj.listen('changePoints', function() { update3D(obj.line) }) }) var renderer = new Renderer(dom, line2Ds) renderer.models.push(wall) renderer.models.push.apply(renderer.models, doors.concat(casements)) renderer.render() var position; return { position: function (posPoint, angle) { if (!position) { position = new Position(posPoint, angle) renderer.models.push(position) } else { position.point = posPoint position.angle = angle } renderer.render() }, renderer: renderer } } })();