UNPKG

@mapgis/webclient-es6-mapboxgl

Version:

243 lines (214 loc) 9.19 kB
import { Common } from '@mapgis/webclient-es6-service'; const { Zondy } = Common; import {Area} from './Area'; import {Color} from './Color'; import {ComputeBoundingBox} from './ComputeBoundingBox'; import {Curve as LevelRendererCurve} from './Curve'; import {Env} from './Env'; import {Event as LevelRendererEvent} from './Event'; import {Http} from './Http'; import {Math as SMath} from './Math'; import {Matrix} from './Matrix'; import {Util} from './Util'; import {Vector as LevelRendererVector} from './Vector'; /** * @private * @class Zondy.LevelRenderer.SUtil */ class SUtil { /** * @function Zondy.LevelRenderer.SUtil.SUtil_smoothBezier * @description 贝塞尔平滑曲线。 * @private * @param {Array} points - 线段顶点数组。 * @param {number} smooth - 平滑等级, 0-1。 * @param {boolean} isLoop - isLoop。 * @param {Array} constraint - 将计算出来的控制点约束在一个包围盒内,比如 [[0, 0], [100, 100]], 这个包围盒会与整个折线的包围盒做一个并集用来约束控制点。 * @param {Array} [originalPosition=[0, 0]] - 参考原点。 * @return {Array} 生成的平滑节点数组。 */ static SUtil_smoothBezier(points, smooth, isLoop, constraint, originalPosition) { if (!originalPosition || originalPosition !== 2) { originalPosition = [0, 0]; } var __OP = originalPosition; var cps = []; var v = []; var v1 = []; var v2 = []; var hasConstraint = !!constraint; var min, max; if (hasConstraint) { min = [Infinity, Infinity]; max = [-Infinity, -Infinity]; let len = points.length; for (let i = 0; i < len; i++) { SUtil.Util_vector.min(min, min, [points[i][0] + __OP[0], points[i][1] + __OP[1]]); SUtil.Util_vector.max(max, max, [points[i][0] + __OP[0], points[i][1] + __OP[1]]); } // 与指定的包围盒做并集 SUtil.Util_vector.min(min, min, constraint[0]); SUtil.Util_vector.max(max, max, constraint[1]); } let len = points.length; for (let i = 0; i < len; i++) { let point = [points[i][0] + __OP[0], points[i][1] + __OP[1]]; let prevPoint; let nextPoint; if (isLoop) { prevPoint = [points[i ? i - 1 : len - 1][0] + __OP[0], points[i ? i - 1 : len - 1][1] + __OP[1]]; nextPoint = [points[(i + 1) % len][0] + __OP[0], points[(i + 1) % len][1] + __OP[1]]; } else { if (i === 0 || i === len - 1) { cps.push([points[i][0] + __OP[0], points[i][1] + __OP[1]]); continue; } else { prevPoint = [points[i - 1][0] + __OP[0], points[i - 1][1] + __OP[1]]; nextPoint = [points[i + 1][0] + __OP[0], points[i + 1][1] + __OP[1]]; } } SUtil.Util_vector.sub(v, nextPoint, prevPoint); // use degree to scale the handle length SUtil.Util_vector.scale(v, v, smooth); let d0 = SUtil.Util_vector.distance(point, prevPoint); let d1 = SUtil.Util_vector.distance(point, nextPoint); let sum = d0 + d1; if (sum !== 0) { d0 /= sum; d1 /= sum; } SUtil.Util_vector.scale(v1, v, -d0); SUtil.Util_vector.scale(v2, v, d1); let cp0 = SUtil.Util_vector.add([], point, v1); let cp1 = SUtil.Util_vector.add([], point, v2); if (hasConstraint) { SUtil.Util_vector.max(cp0, cp0, min); SUtil.Util_vector.min(cp0, cp0, max); SUtil.Util_vector.max(cp1, cp1, min); SUtil.Util_vector.min(cp1, cp1, max); } cps.push(cp0); cps.push(cp1); } if (isLoop) { cps.push(cps.shift()); } return cps; } /** * @function Zondy.LevelRenderer.SUtil.SUtil_smoothSpline * @description 插值折线。 * @private * @param {Array} points - 线段顶点数组。 * @param {boolean} isLoop - isLoop。 * @param {Array} constraint - 将计算出来的控制点约束在一个包围盒内,比如 [[0, 0], [100, 100]], 这个包围盒会与整个折线的包围盒做一个并集用来约束控制点。 * @param {Array} originalPosition - 参考原点。默认值:[0, 0]。 * @return {Array} 生成的平滑节点数组。 */ static SUtil_smoothSpline(points, isLoop, constraint, originalPosition) { if (!originalPosition || originalPosition !== 2) { originalPosition = [0, 0]; } var __OP = originalPosition; var len = points.length; var ret = []; var distance = 0; for (let i = 1; i < len; i++) { distance += SUtil.Util_vector.distance([points[i - 1][0] + __OP[0], points[i - 1][1] + __OP[1]], [points[i][0] + __OP[0], points[i][1] + __OP[1]]); } var segs = distance / 5; segs = segs < len ? len : segs; for (let i = 0; i < segs; i++) { let pos = i / (segs - 1) * (isLoop ? len : len - 1); let idx = Math.floor(pos); let w = pos - idx; let p0; let p1 = [points[idx % len][0] + __OP[0], points[idx % len][1] + __OP[1]]; let p2; let p3; if (!isLoop) { p0 = [points[idx === 0 ? idx : idx - 1][0] + __OP[0], points[idx === 0 ? idx : idx - 1][1] + __OP[1]]; p2 = [points[idx > len - 2 ? len - 1 : idx + 1][0] + __OP[0], points[idx > len - 2 ? len - 1 : idx + 1][1] + __OP[1]]; p3 = [points[idx > len - 3 ? len - 1 : idx + 2][0] + __OP[0], points[idx > len - 3 ? len - 1 : idx + 2][1] + __OP[1]]; } else { p0 = [points[(idx - 1 + len) % len][0] + __OP[0], points[(idx - 1 + len) % len][1] + __OP[1]]; p2 = [points[(idx + 1) % len][0] + __OP[0], points[(idx + 1) % len][1] + __OP[1]]; p3 = [points[(idx + 2) % len][0] + __OP[0], points[(idx + 2) % len][1] + __OP[1]]; } let w2 = w * w; let w3 = w * w2; ret.push([ interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3), interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3) ]); } return ret; // inner Function function interpolate(p0, p1, p2, p3, t, t2, t3) { var v0 = (p2 - p0) * 0.5; var v1 = (p3 - p1) * 0.5; return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1; } } /** * @function Zondy.LevelRenderer.SUtil.SUtil_dashedLineTo * @description 虚线 lineTo。 */ static SUtil_dashedLineTo(ctx, x1, y1, x2, y2, dashLength, customDashPattern) { // http://msdn.microsoft.com/en-us/library/ie/dn265063(v=vs.85).aspx var dashPattern = [5, 5]; dashLength = typeof dashLength != 'number' ? 5 : dashLength; if (ctx.setLineDash) { dashPattern[0] = dashLength; dashPattern[1] = dashLength; if (customDashPattern && (customDashPattern instanceof Array)) { ctx.setLineDash(customDashPattern); } else { ctx.setLineDash(dashPattern); } // ctx.setLineDash(dashPattern); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); return; } var dx = x2 - x1; var dy = y2 - y1; var numDashes = Math.floor( Math.sqrt(dx * dx + dy * dy) / dashLength ); dx = dx / numDashes; dy = dy / numDashes; var flag = true; for (var i = 0; i < numDashes; ++i) { if (flag) { ctx.moveTo(x1, y1); } else { ctx.lineTo(x1, y1); } flag = !flag; x1 += dx; y1 += dy; } ctx.lineTo(x2, y2); } }; // 把所有工具对象放到全局静态变量上,以便直接调用工具方法, // 避免使用工具时频繁的创建工具对象带来的性能消耗。 SUtil.Util_area = new Area(); SUtil.Util_color = new Color(); SUtil.Util_computeBoundingBox = new ComputeBoundingBox(); SUtil.Util_curve = new LevelRendererCurve(); SUtil.Util_env = new Env(); SUtil.Util_event = new LevelRendererEvent(); SUtil.Util_http = new Http(); SUtil.Util_math = new SMath(); SUtil.Util_matrix = new Matrix(); SUtil.Util = new Util(); SUtil.Util_vector = new LevelRendererVector(); export {SUtil}; Zondy.LevelRenderer.SUtil = SUtil;