@sl-utils/map 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +1 -0
- package/package.json +32 -0
- package/src/canvas/index.ts +4 -0
- package/src/canvas/slu-canvas-gif.ts +600 -0
- package/src/canvas/slu-canvas-img.ts +54 -0
- package/src/canvas/slu-canvas-text.ts +179 -0
- package/src/canvas/slu-canvas.ts +188 -0
- package/src/index.ts +0 -0
- package/src/map/canvas-draw.ts +250 -0
- package/src/map/canvas-event.ts +283 -0
- package/src/map/canvas-layer.ts +191 -0
- package/src/utils/slu-map.ts +427 -0
- package/src/utils/txt.ts +251 -0
- package/tsconfig.json +23 -0
- package/types/amap.d.ts +7542 -0
- package/types/core.d.ts +894 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
|
|
2
|
+
import { u_TextSplitMultilineText } from '../utils/txt';
|
|
3
|
+
import { SLUCanvas } from './slu-canvas';
|
|
4
|
+
/**画布绘制文本工具类 */
|
|
5
|
+
export class SLUCanvasText {
|
|
6
|
+
private static ctx: CanvasRenderingContext2D;
|
|
7
|
+
/**绘制文本(包含重叠处理)
|
|
8
|
+
* @param info 文本信息
|
|
9
|
+
* @param textRects 已绘制文本
|
|
10
|
+
* @param ctx 画布
|
|
11
|
+
*/
|
|
12
|
+
public static drawText(
|
|
13
|
+
info: SLTCanvas.Text,
|
|
14
|
+
textRects: SLTCanvas.TextRect[] = [],
|
|
15
|
+
ctx: CanvasRenderingContext2D = this.ctx
|
|
16
|
+
): void {
|
|
17
|
+
let { text = '', maxWidth = 0, font = ctx.font, ifHide } = info;
|
|
18
|
+
if (ifHide === true || !text) return null;
|
|
19
|
+
this.ctx = ctx;
|
|
20
|
+
/**字体配置决定meas的值,所以计算前需要设置配置 */
|
|
21
|
+
SLUCanvas.setCtxPara(ctx, info);
|
|
22
|
+
const texts = this.wordWrap(text, maxWidth, font);
|
|
23
|
+
const textRect = this.calcTextRect(texts, info);
|
|
24
|
+
const ctr = this.avoidOverlap(info, textRect, textRects);
|
|
25
|
+
this.renderTexts(info, texts, textRect, textRects, ctr, ctx);
|
|
26
|
+
}
|
|
27
|
+
/**对文本换行计算,按规则得到多行文本
|
|
28
|
+
* @param text 文本
|
|
29
|
+
* @param ctx 画布
|
|
30
|
+
* @param max 最大宽度
|
|
31
|
+
* @param font 字体
|
|
32
|
+
*/
|
|
33
|
+
private static wordWrap(text: string, max: number, font: string, ctx: CanvasRenderingContext2D = this.ctx): string[] {
|
|
34
|
+
/**强制分行分隔符 */
|
|
35
|
+
let strs = text.split('\n').filter(e => e != '');
|
|
36
|
+
if (max <= 0) return strs;
|
|
37
|
+
let texts: string[] = [];
|
|
38
|
+
strs.forEach((text) => {
|
|
39
|
+
texts.push(...u_TextSplitMultilineText(ctx, text, font, max, true, (str) => {
|
|
40
|
+
return [str.lastIndexOf(',') + 1]
|
|
41
|
+
}))
|
|
42
|
+
})
|
|
43
|
+
return texts
|
|
44
|
+
}
|
|
45
|
+
/**计算得到文本框(无论是否绘制背景框都需要计算)
|
|
46
|
+
* @param texts 文本组
|
|
47
|
+
* @param info 文本配置
|
|
48
|
+
* @param ctx 画布
|
|
49
|
+
*/
|
|
50
|
+
private static calcTextRect(texts: string[], info: SLTCanvas.Text, ctx: CanvasRenderingContext2D = this.ctx): SLTCanvas.TextRect {
|
|
51
|
+
let { point = [20, 20], panel = {}, lineHeight, textAlign, px = 0, py = 0 } = info;
|
|
52
|
+
let w = 0, h = 0, [x0, y0] = point;
|
|
53
|
+
let { actualBoundingBoxDescent = 0 } = ctx.measureText('M');
|
|
54
|
+
h = (lineHeight || actualBoundingBoxDescent) * texts.length;
|
|
55
|
+
w = Math.max(...texts.map(text => ctx.measureText(text).width));
|
|
56
|
+
const { pl = 0, pr = pl, pt = 0, pb = pt } = panel;
|
|
57
|
+
let width = w + pl + pr, height = h + pt + pb;
|
|
58
|
+
if (textAlign === 'center') x0 -= width / 2;
|
|
59
|
+
if (textAlign === 'right') x0 -= width;
|
|
60
|
+
let textRect: SLTCanvas.TextRect = {
|
|
61
|
+
x: x0 + px,
|
|
62
|
+
y: y0 + py,
|
|
63
|
+
width: width,
|
|
64
|
+
height: height
|
|
65
|
+
};
|
|
66
|
+
return textRect;
|
|
67
|
+
}
|
|
68
|
+
/**八个方向查找空隙
|
|
69
|
+
* @param rect 文本范围
|
|
70
|
+
* @param rects 已存在的文本范围
|
|
71
|
+
* @returns [X轴偏移量,Y轴偏移量,状态控制标识 0-7:方位 8:正常显示 9:不显示 ]
|
|
72
|
+
*/
|
|
73
|
+
private static avoidOverlap(info: SLTCanvas.Text, rect: SLTCanvas.TextRect, rects: SLTCanvas.TextRect[]): [number, number, number] {
|
|
74
|
+
const { x, y, width = 0, height = 0 } = rect, { overlap, textAlign } = info, { type = "show", querySpace = 1, maxDistance = 200, minSpacing = 0 } = overlap || {};
|
|
75
|
+
if (type === 'show') return [0, 0, 8];
|
|
76
|
+
let ifOverlap = this.isTextOverlap(rect, rects);
|
|
77
|
+
if (type === 'hide') {
|
|
78
|
+
if (ifOverlap) return [0, 0, 9]
|
|
79
|
+
return [0, 0, 8]
|
|
80
|
+
}
|
|
81
|
+
if (!ifOverlap) {
|
|
82
|
+
return [0, 0, 8];
|
|
83
|
+
} else {
|
|
84
|
+
let flag: boolean = false;
|
|
85
|
+
for (let total = 0; total <= maxDistance; total += querySpace) {
|
|
86
|
+
for (let dir = 0; dir < 8; dir++) {
|
|
87
|
+
/**根据移动方向确定xy的偏移量 dir : 0 上 4下 1-3 右 5-7左 */
|
|
88
|
+
const dirX = dir % 4 === 0 ? 0 : dir < 4 ? 1 : -1, dirY = (dir == 2 || dir == 6) ? 0 : dir < 2 || dir > 6 ? -1 : 1;
|
|
89
|
+
/**不同方位偏移量算法不一样 */
|
|
90
|
+
let px = total * dirX - (dirX < 0 ? width : 0), py = total * dirY - (dirY < 0 ? height : 0);
|
|
91
|
+
// if (!flag) {
|
|
92
|
+
// let w = textAlign == 'center' ? width/2 : 0;
|
|
93
|
+
// /**先左右上下移动文本框的宽度或者一半 */
|
|
94
|
+
// }
|
|
95
|
+
|
|
96
|
+
if (!this.isTextOverlap({ x: x + px, y: y + py, width, height }, rects, minSpacing)) {
|
|
97
|
+
return [px, py, dir]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return [0, 0, 9];
|
|
103
|
+
}
|
|
104
|
+
/**绘制文本
|
|
105
|
+
* @param info 文本配置
|
|
106
|
+
* @param texts 文本字符串组
|
|
107
|
+
* @param rect 文本框
|
|
108
|
+
* @param textRects 已绘制文本框
|
|
109
|
+
* @param ctr 偏移控制
|
|
110
|
+
*/
|
|
111
|
+
private static renderTexts(info: SLTCanvas.Text, texts: string[], rect: SLTCanvas.TextRect, textRects: SLTCanvas.TextRect[], ctr: [number, number, number], ctx: CanvasRenderingContext2D) {
|
|
112
|
+
const [px, py, status] = ctr,
|
|
113
|
+
{ panel = {}, overlap = {}, textAlign = 'center', px: upx = 0, py: upy = 0, point = [0, 0] } = info,
|
|
114
|
+
{ pl = 0, pt = 0, pb = pt, pr = pl } = panel,
|
|
115
|
+
{ line } = overlap,
|
|
116
|
+
{ width = 0, height = 0 } = rect,
|
|
117
|
+
[x0, y0] = point;
|
|
118
|
+
if (status === 9) return;
|
|
119
|
+
rect.x += px, rect.y += py;
|
|
120
|
+
textRects.push({ ...rect });
|
|
121
|
+
if (px != 0 || py != 0 && line) {
|
|
122
|
+
//status 0正上 1右上 2右 3右下 4正下 5左下 6左 7左上
|
|
123
|
+
let { x: x1, y: y1 } = rect;
|
|
124
|
+
switch (status) {
|
|
125
|
+
case 0: x1 = x1, y1 = y1 + height; break;
|
|
126
|
+
case 1: x1 = x1, y1 = y1 + height; break;
|
|
127
|
+
case 2: x1 = x1, y1 = y1; break;
|
|
128
|
+
case 3: x1 = x1, y1 = y1; break;
|
|
129
|
+
case 4: x1 = x1, y1 = y1; break;
|
|
130
|
+
case 5: x1 = x1 + width, y1 = y1; break;
|
|
131
|
+
case 6: x1 = x1 + width, y1 = y1; break;
|
|
132
|
+
case 7: x1 = x1 + width, y1 = y1 + height; break;
|
|
133
|
+
}
|
|
134
|
+
SLUCanvas.drawLine({ ...line, points: [[x0, y0], [x1, y1]] }, ctx);
|
|
135
|
+
}
|
|
136
|
+
if (panel) {
|
|
137
|
+
SLUCanvas.drawRect(
|
|
138
|
+
{
|
|
139
|
+
point: [rect.x, rect.y],
|
|
140
|
+
width: rect.width,
|
|
141
|
+
height: rect.height,
|
|
142
|
+
radius: panel.radius,
|
|
143
|
+
...panel,
|
|
144
|
+
},
|
|
145
|
+
ctx
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
SLUCanvas.setCtxPara(ctx, info);
|
|
149
|
+
this.renderMultiText(texts, [rect.x + pl, rect.y + pt], info, ctx);
|
|
150
|
+
SLUCanvas.setCtxPara(ctx);
|
|
151
|
+
}
|
|
152
|
+
/**绘制多行文本*/
|
|
153
|
+
public static renderMultiText(texts: string[], start: number[], info: SLTCanvas.Text, ctx: CanvasRenderingContext2D) {
|
|
154
|
+
let [x, y] = start;
|
|
155
|
+
const { lineHeight, ifShadow } = info;
|
|
156
|
+
let { actualBoundingBoxDescent } = ctx.measureText('M');
|
|
157
|
+
texts.forEach(text => {
|
|
158
|
+
/**文本居中 需偏移量 */
|
|
159
|
+
let fontTop = lineHeight && lineHeight > actualBoundingBoxDescent ? (lineHeight - actualBoundingBoxDescent) / 2 : 0;
|
|
160
|
+
/**行高 变化量 */
|
|
161
|
+
let dH = lineHeight || actualBoundingBoxDescent;
|
|
162
|
+
if (ifShadow) /**绘制描边 */ ctx.strokeText(text, x, y + fontTop);
|
|
163
|
+
/**绘制文本 */
|
|
164
|
+
ctx.fillText(text, x, y + fontTop);
|
|
165
|
+
y += dH;
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
/**文本是否重叠 */
|
|
169
|
+
private static isTextOverlap(rect: SLTCanvas.TextRect, rects: SLTCanvas.TextRect[], minSpacing: number = 0) {
|
|
170
|
+
for (const eRect of rects) {
|
|
171
|
+
const { x, y, width = 0, height = 0 } = rect;
|
|
172
|
+
const { x: ex, y: ey = 0, width: ew = 0, height: eh = 0 } = eRect;
|
|
173
|
+
if (!(ex > x + width + minSpacing || ex + ew + minSpacing < x || ey > y + height + minSpacing || ey + eh + minSpacing < y)) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// import { SLTCanvas.Line, SLPCanvas, SLTCanvas.Polygon, SLTCanvas.Rect, SLTCanvas.Text, SLTCanvas.Arc, SLTCanvas.Image } from "./slu-canvas.model";
|
|
2
|
+
export class SLUCanvas {
|
|
3
|
+
/**canvas画布的工具类*/
|
|
4
|
+
constructor() { }
|
|
5
|
+
/** */
|
|
6
|
+
protected static ctx: CanvasRenderingContext2D;
|
|
7
|
+
/**绘图的默认配置 */
|
|
8
|
+
static readonly ctxFig: SLPCanvas = {
|
|
9
|
+
alpha: 1,
|
|
10
|
+
widthLine: 1,
|
|
11
|
+
colorLine: '#FFFFFF',
|
|
12
|
+
colorFill: '#EE3434',
|
|
13
|
+
dash: [10, 0],
|
|
14
|
+
dashOff: 0,
|
|
15
|
+
fillAlpha: 1,
|
|
16
|
+
font: '14px serif',
|
|
17
|
+
textBaseline: "top",
|
|
18
|
+
globalCompositeOperation: 'source-over',
|
|
19
|
+
shadowBlur: 0,
|
|
20
|
+
shadowColor: '#000000',
|
|
21
|
+
};
|
|
22
|
+
/**绘制小圆点 */
|
|
23
|
+
public static drawArc(arc: SLTCanvas.Arc, ctx: CanvasRenderingContext2D = this.ctx): SLUCanvas {
|
|
24
|
+
if (arc.ifHide === true) return this;
|
|
25
|
+
let { point, points = [], size = 10 } = arc;
|
|
26
|
+
if (point) points = [...points, point];
|
|
27
|
+
this.setCtxPara(ctx, arc);
|
|
28
|
+
for (let i = 0, len = points.length; i < len; i++) {
|
|
29
|
+
ctx.beginPath();
|
|
30
|
+
const e = points[i]!;
|
|
31
|
+
ctx.arc(e[0], e[1], size, 0, 2 * Math.PI, false);
|
|
32
|
+
ctx.stroke();
|
|
33
|
+
ctx.globalAlpha = arc.fillAlpha == undefined ? 1 : arc.fillAlpha;
|
|
34
|
+
ctx.fill();
|
|
35
|
+
}
|
|
36
|
+
this.setCtxPara(ctx);
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
/**绘制矩形 */
|
|
40
|
+
public static drawRect(rect: SLTCanvas.Rect, ctx: CanvasRenderingContext2D = this.ctx) {
|
|
41
|
+
if (rect.ifHide === true) return this;
|
|
42
|
+
let { point, points = [point], width = 0, height = 0, radius = [0, 0, 0, 0] } = rect;
|
|
43
|
+
this.setCtxPara(ctx, rect);
|
|
44
|
+
for (let i = 0; i < points.length; i++) {
|
|
45
|
+
let [x, y] = points[i] || [0, 0];
|
|
46
|
+
ctx.beginPath();
|
|
47
|
+
ctx['roundRect'](x, y, width, height, radius);
|
|
48
|
+
ctx.stroke();
|
|
49
|
+
ctx.globalAlpha = rect.fillAlpha == undefined ? 1 : rect.fillAlpha;
|
|
50
|
+
ctx.fill();
|
|
51
|
+
ctx.closePath();
|
|
52
|
+
// radius = 3;
|
|
53
|
+
// x = x + 300;
|
|
54
|
+
// ctx.beginPath();
|
|
55
|
+
// ctx.moveTo(x + radius, y);
|
|
56
|
+
// ctx.arcTo(x + width, y, x + width, y + height, radius);
|
|
57
|
+
// ctx.arcTo(x + width, y + height, x, y + height, radius);
|
|
58
|
+
// ctx.arcTo(x, y + height, x, y, radius);
|
|
59
|
+
// ctx.arcTo(x, y, x + width, y, radius);
|
|
60
|
+
// ctx.closePath();
|
|
61
|
+
// ctx.stroke();
|
|
62
|
+
}
|
|
63
|
+
this.setCtxPara(ctx);
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
/**画绘制多边形*/
|
|
67
|
+
public static drawPolygon(rect: SLTCanvas.Polygon, ctx: CanvasRenderingContext2D = this.ctx): SLUCanvas {
|
|
68
|
+
let { points = [] } = rect;
|
|
69
|
+
if (rect.ifHide === true || points.length < 2) return this;
|
|
70
|
+
this.setCtxPara(ctx, rect);
|
|
71
|
+
for (let i = 0, len = points.length; i < len; i++) {
|
|
72
|
+
let [x, y] = points[i];
|
|
73
|
+
if (i == 0) {
|
|
74
|
+
ctx.beginPath();
|
|
75
|
+
ctx.moveTo(x, y);
|
|
76
|
+
} else if (i == len - 1) {
|
|
77
|
+
ctx.lineTo(x, y);
|
|
78
|
+
ctx.closePath();
|
|
79
|
+
ctx.globalAlpha = rect.fillAlpha == undefined ? 1 : rect.fillAlpha;
|
|
80
|
+
ctx.fill();
|
|
81
|
+
if (ctx.lineWidth > 0) {
|
|
82
|
+
ctx.globalAlpha = rect.alpha || 1;
|
|
83
|
+
ctx.stroke();
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
ctx.lineTo(x, y);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
this.setCtxPara(ctx);
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
/**画线*/
|
|
93
|
+
public static drawLine(line: SLTCanvas.Line, ctx: CanvasRenderingContext2D = this.ctx): SLUCanvas {
|
|
94
|
+
if (line.ifHide === true) return this;
|
|
95
|
+
let { points = [] } = line;
|
|
96
|
+
if (points.length < 2) return this;
|
|
97
|
+
this.setCtxPara(ctx, line);
|
|
98
|
+
let s = points[0] || [], lineWidth = line.widthLine || 1;
|
|
99
|
+
ctx.beginPath();
|
|
100
|
+
ctx.moveTo(s[0], s[1]);
|
|
101
|
+
for (let i = 1, len = points.length; i < len; i++) {
|
|
102
|
+
let point = points[i];
|
|
103
|
+
ctx.lineTo(point[0], point[1]);
|
|
104
|
+
}
|
|
105
|
+
ctx.stroke();
|
|
106
|
+
this.setCtxPara(ctx);
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
/**画贝塞尔曲线*/
|
|
110
|
+
public static drawBezierLine(line: SLTCanvas.Line, ctx: CanvasRenderingContext2D = this.ctx): SLUCanvas {
|
|
111
|
+
if (line.ifHide === true) return this;
|
|
112
|
+
let { points = [] } = line;
|
|
113
|
+
if (points.length < 2) return this;
|
|
114
|
+
this.setCtxPara(ctx, line);
|
|
115
|
+
let s = points[0],
|
|
116
|
+
degree = line.degree;
|
|
117
|
+
ctx.beginPath();
|
|
118
|
+
ctx.moveTo(s[0], s[1]);
|
|
119
|
+
for (let i = 1, len = points.length; i < len; i++) {
|
|
120
|
+
let s = points[i - 1],
|
|
121
|
+
e = points[i];
|
|
122
|
+
let c = this.getBezierCtrlPoint(s, e, degree);
|
|
123
|
+
ctx.quadraticCurveTo(c[0], c[1], e[0], e[1]);
|
|
124
|
+
}
|
|
125
|
+
ctx.stroke();
|
|
126
|
+
this.setCtxPara(ctx);
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
/**创建一个画布 */
|
|
130
|
+
public static createCanvas(): HTMLCanvasElement {
|
|
131
|
+
return document.createElement('canvas');
|
|
132
|
+
}
|
|
133
|
+
/**获取贝塞尔曲线的控制点
|
|
134
|
+
* @param s:起点
|
|
135
|
+
* @param e:终点
|
|
136
|
+
* @param degree:曲度等级(越大越弯曲)
|
|
137
|
+
*/
|
|
138
|
+
public static getBezierCtrlPoint(s: [number, number], e: [number, number], degree: number = 1): [number, number] {
|
|
139
|
+
const e0 = s,
|
|
140
|
+
e1 = e,
|
|
141
|
+
c = [(e0[0] + e1[0]) / 2, (e0[1] + e1[1]) / 2],
|
|
142
|
+
d = degree;
|
|
143
|
+
let x = c[0] - e0[0],
|
|
144
|
+
y = c[1] - e0[1];
|
|
145
|
+
/**中点到起点间的距离 */
|
|
146
|
+
let len = Math.sqrt(x * x + y * y);
|
|
147
|
+
/**角度 */
|
|
148
|
+
let angle = Math.PI / 2 - Math.asin(y / len);
|
|
149
|
+
let xd = d * Math.cos(angle) * len,
|
|
150
|
+
yd = (d * Math.sin(angle) * len * x) / Math.abs(x);
|
|
151
|
+
xd = isNaN(xd) ? 0 : xd;
|
|
152
|
+
yd = isNaN(yd) ? 0 : yd;
|
|
153
|
+
let curve: [number, number] = [c[0] + xd, c[1] - yd];
|
|
154
|
+
return curve;
|
|
155
|
+
}
|
|
156
|
+
/**设置画布的相关配置
|
|
157
|
+
* @param fig 画布属性配置
|
|
158
|
+
* @param ctx 2D画布渲染上下文
|
|
159
|
+
*/
|
|
160
|
+
public static setCtxPara(ctx: CanvasRenderingContext2D, fig: SLPCanvas = {}): CanvasRenderingContext2D {
|
|
161
|
+
this.ctx = ctx;
|
|
162
|
+
this.deletePara(fig);
|
|
163
|
+
fig = Object.assign({}, this.ctxFig, fig);
|
|
164
|
+
ctx.globalAlpha = fig.alpha!;
|
|
165
|
+
ctx.globalCompositeOperation = fig.globalCompositeOperation!;
|
|
166
|
+
ctx.fillStyle = fig.colorFill!;
|
|
167
|
+
ctx.strokeStyle = fig.colorLine!;
|
|
168
|
+
ctx.lineWidth = fig.widthLine!;
|
|
169
|
+
ctx.shadowColor = fig.shadowColor!;
|
|
170
|
+
ctx.shadowBlur = fig.shadowBlur!;
|
|
171
|
+
ctx.font = fig.font!;
|
|
172
|
+
ctx.textBaseline = fig.textBaseline!;
|
|
173
|
+
ctx.setLineDash(fig.dash!);
|
|
174
|
+
ctx.lineDashOffset = fig.dashOff!;
|
|
175
|
+
return ctx;
|
|
176
|
+
}
|
|
177
|
+
/**移除掉值为 undefined 或 null 的属性,方便赋值 */
|
|
178
|
+
private static deletePara(obj: any = {}) {
|
|
179
|
+
for (const key in obj) {
|
|
180
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
181
|
+
const ele = obj[key];
|
|
182
|
+
if (ele === undefined || ele === null) {
|
|
183
|
+
Reflect.deleteProperty(obj, key);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
package/src/index.ts
ADDED
|
File without changes
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import * as L from 'leaflet';
|
|
2
|
+
import { u_arrItemDel, u_mapGetMapSize, u_mapGetPointByLatlng, u_mapGetPointsByLatlngs, u_mapGetSizeByMap } from '../utils/slu-map'
|
|
3
|
+
import { SLUCanvas, SLUCanvasGif, SLUCanvasImg, SLUCanvasText } from '../canvas';
|
|
4
|
+
|
|
5
|
+
/** 地图canvas基础图形绘制类 点(arc) 线(line BezierLine) 多边形(rect) 图片(img)*/
|
|
6
|
+
export class MapCanvasDraw {
|
|
7
|
+
constructor(map: AMAP.Map | L.Map, canvas: HTMLCanvasElement) {
|
|
8
|
+
this.map = map;
|
|
9
|
+
this.canvas = canvas;
|
|
10
|
+
this.ctx = canvas.getContext('2d')!;
|
|
11
|
+
}
|
|
12
|
+
private canvas: HTMLCanvasElement;
|
|
13
|
+
protected ctx: CanvasRenderingContext2D;
|
|
14
|
+
protected map: AMAP.Map | L.Map;
|
|
15
|
+
private gif: SLUCanvasGif;
|
|
16
|
+
/**所有的小圆数据 */
|
|
17
|
+
protected _allArcs: MapArc[] = [];
|
|
18
|
+
/**所有的线数据 */
|
|
19
|
+
protected _allLines: MapLine[] = [];
|
|
20
|
+
/**所有的贝塞尔曲线数据 */
|
|
21
|
+
protected _allBLins: MapLine[] = [];
|
|
22
|
+
/**所有的多边形数据 */
|
|
23
|
+
protected _allRects: MapRect[] = [];
|
|
24
|
+
/**所有的文本数据 */
|
|
25
|
+
protected _allTexts: MapText[] = [];
|
|
26
|
+
/**所有的图片数据 */
|
|
27
|
+
protected _allImgs: MapImage[] = [];
|
|
28
|
+
/**所有的Gif数据 */
|
|
29
|
+
protected _allGifs: MapGif[] = [];
|
|
30
|
+
protected get zoom(): number {
|
|
31
|
+
return this.map.getZoom();
|
|
32
|
+
}
|
|
33
|
+
/** 清空并重新设置画布 */
|
|
34
|
+
public reSetCanvas(): void {
|
|
35
|
+
let { canvas, map, ctx } = this;
|
|
36
|
+
const { w, h } = u_mapGetMapSize(map);
|
|
37
|
+
canvas.style.width = w + 'px';
|
|
38
|
+
canvas.style.height = h + 'px';
|
|
39
|
+
//清除画布
|
|
40
|
+
canvas.width = w;
|
|
41
|
+
canvas.height = h;
|
|
42
|
+
}
|
|
43
|
+
/**绘制所有需要绘制的类(按drawIndex顺序) */
|
|
44
|
+
public drawMapAll() {
|
|
45
|
+
this.reSetCanvas();
|
|
46
|
+
this.drawByIndex();
|
|
47
|
+
}
|
|
48
|
+
/**绘制通过index */
|
|
49
|
+
protected async drawByIndex() {
|
|
50
|
+
let textRects: SLTCanvas.TextRect[] = [], that = this, { ctx, zoom } = that,
|
|
51
|
+
all: any[] = that._allRects.map((e) => ({ ...e, mold: 'R' }));
|
|
52
|
+
all = all.concat(that._allLines.map((e) => ({ ...e, mold: 'L' })));
|
|
53
|
+
all = all.concat(that._allBLins.map((e) => ({ ...e, mold: 'B' })));
|
|
54
|
+
all = all.concat(that._allArcs.map((e) => ({ ...e, mold: 'A' })));
|
|
55
|
+
all = all.concat(that._allTexts.map((e) => ({ ...e, mold: 'T' })));
|
|
56
|
+
all = all.concat(that._allImgs.map((e) => ({ ...e, mold: 'I' })));
|
|
57
|
+
all = all.concat(that._allGifs.map((e) => ({ ...e, mold: 'G' })));
|
|
58
|
+
all.sort((a, b) => (a.index || 0) - (b.index || 0));
|
|
59
|
+
all.forEach((e, index) => {
|
|
60
|
+
let { minZoom = 0, maxZoom = 50, overlap } = e;
|
|
61
|
+
if (zoom >= minZoom && zoom <= maxZoom) {
|
|
62
|
+
that.transformXY(e);
|
|
63
|
+
switch (e.mold) {
|
|
64
|
+
case 'A':
|
|
65
|
+
that.transformArcSize(e);
|
|
66
|
+
SLUCanvas.drawArc(e, ctx);
|
|
67
|
+
break;
|
|
68
|
+
case 'L':
|
|
69
|
+
SLUCanvas.drawLine(e, ctx);
|
|
70
|
+
break;
|
|
71
|
+
case 'B':
|
|
72
|
+
SLUCanvas.drawBezierLine(e, ctx);
|
|
73
|
+
break;
|
|
74
|
+
case 'R':
|
|
75
|
+
SLUCanvas.drawPolygon(e, ctx);
|
|
76
|
+
break;
|
|
77
|
+
case 'T':
|
|
78
|
+
SLUCanvasText.drawText(e, textRects, ctx);
|
|
79
|
+
break;
|
|
80
|
+
case 'I':
|
|
81
|
+
that.transformImageSize(e);
|
|
82
|
+
SLUCanvasImg.drawImg(e, ctx);
|
|
83
|
+
break;
|
|
84
|
+
case 'G':
|
|
85
|
+
that.transformImageSize(e);
|
|
86
|
+
that.gif = that.gif || new SLUCanvasGif();
|
|
87
|
+
that.gif.loadGIF(e, ctx);
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**设置原点 */
|
|
94
|
+
public setAllArcs(arcs: MapArc[]) {
|
|
95
|
+
this._allArcs = arcs;
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
/**设置线数据 */
|
|
99
|
+
public setAllLines(lines: MapLine[]) {
|
|
100
|
+
this._allLines = lines;
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
/**设置贝塞尔曲线数据 */
|
|
104
|
+
public setAllBezierLines(lines: MapLine[]) {
|
|
105
|
+
this._allBLins = lines;
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
/**设置多边形数据 */
|
|
109
|
+
public setAllRects(rects: MapRect[]) {
|
|
110
|
+
this._allRects = rects;
|
|
111
|
+
return this;
|
|
112
|
+
}
|
|
113
|
+
/**设置文本数据 */
|
|
114
|
+
public setAllTexts(texts: MapText[]) {
|
|
115
|
+
this._allTexts = texts;
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
/**设置图片数据 */
|
|
119
|
+
public setAllImgs(imgs: MapImage[]) {
|
|
120
|
+
this._allImgs = imgs;
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
/**设置图片数据 */
|
|
124
|
+
public setAllGifs(gifs: MapGif[]) {
|
|
125
|
+
this._allGifs = gifs;
|
|
126
|
+
return this;
|
|
127
|
+
}
|
|
128
|
+
/**增加原点 */
|
|
129
|
+
public addArc(arc: MapArc) {
|
|
130
|
+
if (!arc.latlngs && !arc.latlng) return this;
|
|
131
|
+
this._allArcs.push(arc);
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
/**增加线 */
|
|
135
|
+
public addLine(line: MapLine) {
|
|
136
|
+
if (!line.latlngs) return this;
|
|
137
|
+
this._allLines.push(line);
|
|
138
|
+
return this;
|
|
139
|
+
}
|
|
140
|
+
/**增加贝塞尔曲线 */
|
|
141
|
+
public addBezierLine(line: MapLine) {
|
|
142
|
+
if (!line.latlngs) return this;
|
|
143
|
+
this._allBLins.push(line);
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
/**增加多边形 */
|
|
147
|
+
public addRect(rect: MapRect) {
|
|
148
|
+
if (!rect.latlngs) return this;
|
|
149
|
+
this._allRects.push(rect);
|
|
150
|
+
return this;
|
|
151
|
+
}
|
|
152
|
+
/**增加文本 */
|
|
153
|
+
public addText(text: MapText) {
|
|
154
|
+
if (!text.latlngs && !text.latlng) return this;
|
|
155
|
+
this._allTexts.push(text);
|
|
156
|
+
return this;
|
|
157
|
+
}
|
|
158
|
+
/**增加图片 */
|
|
159
|
+
public addImg(img: MapImage) {
|
|
160
|
+
if (!img.latlngs && !img.latlng) return this;
|
|
161
|
+
this._allImgs.push(img);
|
|
162
|
+
return this;
|
|
163
|
+
}
|
|
164
|
+
/**删除指定圆点 */
|
|
165
|
+
public delArc(arc: MapArc) {
|
|
166
|
+
u_arrItemDel(this._allArcs, arc);
|
|
167
|
+
return this;
|
|
168
|
+
}
|
|
169
|
+
/**删除指定线 */
|
|
170
|
+
public delLine(line: MapLine) {
|
|
171
|
+
u_arrItemDel(this._allLines, line);
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
/**删除指定贝塞尔曲线 */
|
|
175
|
+
public delBezierLine(line: MapLine) {
|
|
176
|
+
u_arrItemDel(this._allBLins, line);
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
179
|
+
/**删除指定多边形 */
|
|
180
|
+
public delRect(rect: MapRect) {
|
|
181
|
+
u_arrItemDel(this._allRects, rect);
|
|
182
|
+
return this;
|
|
183
|
+
}
|
|
184
|
+
/**删除指定文本 */
|
|
185
|
+
public delText(text: MapText) {
|
|
186
|
+
u_arrItemDel(this._allTexts, text);
|
|
187
|
+
return this;
|
|
188
|
+
}
|
|
189
|
+
/**删除指定Img */
|
|
190
|
+
public delImg(img: MapImage) {
|
|
191
|
+
u_arrItemDel(this._allImgs, img);
|
|
192
|
+
return this;
|
|
193
|
+
}
|
|
194
|
+
/**清空
|
|
195
|
+
* @param type 不填清空所有内容数据
|
|
196
|
+
*/
|
|
197
|
+
public delAll(type: 'all' | 'text' | 'arc' | 'line' | 'bezier' | 'rect' | 'img' | 'gif' = 'all') {
|
|
198
|
+
const that = this;
|
|
199
|
+
switch (type) {
|
|
200
|
+
case 'arc':
|
|
201
|
+
that._allArcs = [];
|
|
202
|
+
break;
|
|
203
|
+
case 'line':
|
|
204
|
+
that._allLines = [];
|
|
205
|
+
break;
|
|
206
|
+
case 'bezier':
|
|
207
|
+
that._allBLins = [];
|
|
208
|
+
break;
|
|
209
|
+
case 'rect':
|
|
210
|
+
that._allRects = [];
|
|
211
|
+
break;
|
|
212
|
+
case 'img':
|
|
213
|
+
that._allImgs = [];
|
|
214
|
+
break;
|
|
215
|
+
case 'gif':
|
|
216
|
+
that._allGifs = [];
|
|
217
|
+
break;
|
|
218
|
+
case 'text':
|
|
219
|
+
that._allTexts = [];
|
|
220
|
+
break;
|
|
221
|
+
case 'all':
|
|
222
|
+
that._allArcs = [];
|
|
223
|
+
that._allLines = [];
|
|
224
|
+
that._allBLins = [];
|
|
225
|
+
that._allRects = [];
|
|
226
|
+
that._allImgs = [];
|
|
227
|
+
that._allGifs = [];
|
|
228
|
+
that._allTexts = [];
|
|
229
|
+
}
|
|
230
|
+
return that;
|
|
231
|
+
}
|
|
232
|
+
/**将对象上经纬度数据(latlngs,latlng)变换为像素XY的数据(points,point)
|
|
233
|
+
* latlngs为undefined,points也为undefined
|
|
234
|
+
* latlng为undefined,point为[0,0]
|
|
235
|
+
*/
|
|
236
|
+
public transformXY(info: MapPoint & SLTCanvas.Point) {
|
|
237
|
+
info.points = u_mapGetPointsByLatlngs(this.map, info.latlngs);
|
|
238
|
+
info.point = u_mapGetPointByLatlng(this.map, info.latlng);
|
|
239
|
+
}
|
|
240
|
+
/**设置固定大小的图片 */
|
|
241
|
+
public transformImageSize(img: MapImage) {
|
|
242
|
+
let [x, y] = u_mapGetSizeByMap(this.map, img)
|
|
243
|
+
img.size = [x, y];
|
|
244
|
+
}
|
|
245
|
+
private transformArcSize(arc: MapArc) {
|
|
246
|
+
let [x, y] = u_mapGetSizeByMap(this.map, arc);
|
|
247
|
+
/**经度的差值为X故 */
|
|
248
|
+
arc.size = x;
|
|
249
|
+
}
|
|
250
|
+
}
|