jmgraph 3.2.16 → 3.2.18

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.
Files changed (77) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +251 -428
  3. package/build/gulpfile.js +142 -142
  4. package/build/package-lock.json +10666 -0
  5. package/build/package.json +71 -71
  6. package/dev.js +9 -9
  7. package/dist/jmgraph.core.min.js +1 -1
  8. package/dist/jmgraph.core.min.js.map +1 -1
  9. package/dist/jmgraph.js +3500 -2668
  10. package/dist/jmgraph.min.js +1 -1
  11. package/example/ball.html +216 -216
  12. package/example/base.html +111 -111
  13. package/example/canvas.html +53 -53
  14. package/example/cell.html +283 -283
  15. package/example/controls/arc.html +128 -128
  16. package/example/controls/arrowline.html +77 -77
  17. package/example/controls/bezier.html +298 -298
  18. package/example/controls/img.html +96 -96
  19. package/example/controls/label.html +86 -86
  20. package/example/controls/line.html +172 -172
  21. package/example/controls/prismatic.html +62 -62
  22. package/example/controls/rect.html +63 -63
  23. package/example/controls/resize.html +111 -111
  24. package/example/controls/test.html +359 -359
  25. package/example/es.html +69 -69
  26. package/example/es5module.html +62 -63
  27. package/example/heartarc.html +115 -115
  28. package/example/index.html +46 -46
  29. package/example/js/require.js +4 -4
  30. package/example/love/img/bling/bling.tps +265 -265
  31. package/example/love/img/bling.json +87 -87
  32. package/example/love/img/bling.tps +295 -295
  33. package/example/love/img/love.json +95 -95
  34. package/example/love/img/love.tps +315 -315
  35. package/example/love/img/qq/qq.tps +399 -399
  36. package/example/love/img/qq.json +242 -242
  37. package/example/love/index.html +40 -40
  38. package/example/love/js/game.js +558 -558
  39. package/example/music.html +210 -210
  40. package/example/node/test.js +137 -137
  41. package/example/pdf.html +186 -186
  42. package/example/progress.html +172 -172
  43. package/example/pso.html +147 -147
  44. package/example/sort.html +804 -815
  45. package/example/tweenjs.html +83 -83
  46. package/example/webgl.html +278 -278
  47. package/example/xfj/index.html +331 -331
  48. package/example/xfj/shake.js +48 -48
  49. package/example/xfj/testori.html +75 -75
  50. package/index.js +99 -99
  51. package/package.json +58 -56
  52. package/src/core/jmControl.js +1376 -1531
  53. package/src/core/jmEvents.js +240 -281
  54. package/src/core/jmGradient.js +231 -231
  55. package/src/core/jmGraph.js +569 -569
  56. package/src/core/jmList.js +92 -157
  57. package/src/core/jmObject.js +83 -103
  58. package/src/core/jmPath.js +35 -35
  59. package/src/core/jmProperty.js +71 -110
  60. package/src/core/jmShadow.js +65 -65
  61. package/src/core/jmUtils.js +906 -919
  62. package/src/lib/earcut.js +680 -680
  63. package/src/lib/earcut.md +73 -73
  64. package/src/lib/webgl/base.js +522 -452
  65. package/src/lib/webgl/core/buffer.js +48 -48
  66. package/src/lib/webgl/core/mapSize.js +40 -40
  67. package/src/lib/webgl/core/mapType.js +43 -43
  68. package/src/lib/webgl/core/program.js +138 -138
  69. package/src/lib/webgl/core/shader.js +13 -13
  70. package/src/lib/webgl/core/texture.js +60 -60
  71. package/src/lib/webgl/gradient.js +168 -168
  72. package/src/lib/webgl/index.js +137 -11
  73. package/src/lib/webgl/path.js +568 -561
  74. package/src/shapes/jmArrowLine.js +36 -36
  75. package/src/shapes/jmImage.js +244 -244
  76. package/src/shapes/jmLabel.js +271 -271
  77. package/src/shapes/jmResize.js +332 -330
@@ -1,920 +1,907 @@
1
-
2
- import { jmList } from './jmList.js';
3
-
4
- const colorKeywords = {
5
- aliceblue: "#f0f8ff",
6
- antiquewhite: "#faebd7",
7
- aqua: "#00ffff",
8
- aquamarine: "#7fffd4",
9
- azure: "#f0ffff",
10
- beige: "#f5f5dc",
11
- bisque: "#ffe4c4",
12
- black: "#000000",
13
- blanchedalmond: "#ffebcd",
14
- blue: "#0000ff",
15
- blueviolet: "#8a2be2",
16
- brown: "#a52a2a",
17
- burlywood: "#deb887",
18
- cadetblue: "#5f9ea0",
19
- chartreuse: "#7fff00",
20
- chocolate: "#d2691e",
21
- coral: "#ff7f50",
22
- cornflowerblue: "#6495ed",
23
- cornsilk: "#fff8dc",
24
- crimson: "#dc143c",
25
- cyan: "#00ffff",
26
- darkblue: "#00008b",
27
- darkcyan: "#008b8b",
28
- darkgoldenrod: "#b8860b",
29
- darkgray: "#a9a9a9",
30
- darkgreen: "#006400",
31
- darkkhaki: "#bdb76b",
32
- darkmagenta: "#8b008b",
33
- darkolivegreen: "#556b2f",
34
- darkorange: "#ff8c00",
35
- darkorchid: "#9932cc",
36
- darkred: "#8b0000",
37
- darksalmon: "#e9967a",
38
- darkseagreen: "#8fbc8f",
39
- darkslateblue: "#483d8b",
40
- darkslategray: "#2f4f4f",
41
- darkturquoise: "#00ced1",
42
- darkviolet: "#9400d3",
43
- deeppink: "#ff1493",
44
- deepskyblue: "#00bfff",
45
- dimgray: "#696969",
46
- dodgerblue: "#1e90ff",
47
- firebrick: "#b22222",
48
- floralwhite: "#fffaf0",
49
- forestgreen: "#228b22",
50
- fuchsia: "#ff00ff",
51
- gainsboro: "#dcdcdc",
52
- ghostwhite: "#f8f8ff",
53
- gold: "#ffd700",
54
- goldenrod: "#daa520",
55
- gray: "#808080",
56
- green: "#008000",
57
- greenyellow: "#adff2f",
58
- grey: "#808080",
59
- honeydew: "#f0fff0",
60
- hotpink: "#ff69b4",
61
- indianred: "#cd5c5c",
62
- indigo: "#4b0082",
63
- ivory: "#fffff0",
64
- khaki: "#f0e68c",
65
- lavender: "#e6e6fa",
66
- lavenderblush: "#fff0f5",
67
- lawngreen: "#7cfc00",
68
- lemonchiffon: "#fffacd",
69
- lightblue: "#add8e6",
70
- lightcoral: "#f08080",
71
- lightcyan: "#e0ffff",
72
- lightgoldenrodyellow: "#fafad2",
73
- lightgrey: "#d3d3d3",
74
- lightgreen: "#90ee90",
75
- lightpink: "#ffb6c1",
76
- lightsalmon: "#ffa07a",
77
- lightseagreen: "#20b2aa",
78
- lightskyblue: "#87cefa",
79
- lightslategray: "#778899",
80
- lightsteelblue: "#b0c4de",
81
- lightyellow: "#ffffe0",
82
- lime: "#00ff00",
83
- limegreen: "#32cd32",
84
- linen: "#faf0e6",
85
- magenta: "#ff00ff",
86
- maroon: "#800000",
87
- mediumaquamarine: "#66cdaa",
88
- mediumblue: "#0000cd",
89
- mediumorchid: "#ba55d3",
90
- mediumpurple: "#9370d8",
91
- mediumseagreen: "#3cb371",
92
- mediumslateblue: "#7b68ee",
93
- mediumspringgreen: "#00fa9a",
94
- mediumturquoise: "#48d1cc",
95
- mediumvioletred: "#c71585",
96
- midnightblue: "#191970",
97
- mintcream: "#f5fffa",
98
- mistyrose: "#ffe4e1",
99
- moccasin: "#ffe4b5",
100
- navajowhite: "#ffdead",
101
- navy: "#000080",
102
- oldlace: "#fdf5e6",
103
- olive: "#808000",
104
- olivedrab: "#6b8e23",
105
- orange: "#ffa500",
106
- orangered: "#ff4500",
107
- orchid: "#da70d6",
108
- palegoldenrod: "#eee8aa",
109
- palegreen: "#98fb98",
110
- paleturquoise: "#afeeee",
111
- palevioletred: "#d87093",
112
- papayawhip: "#ffefd5",
113
- peachpuff: "#ffdab9",
114
- peru: "#cd853f",
115
- pink: "#ffc0cb",
116
- plum: "#dda0dd",
117
- powderblue: "#b0e0e6",
118
- purple: "#800080",
119
- red: "#ff0000",
120
- rosybrown: "#bc8f8f",
121
- royalblue: "#4169e1",
122
- saddlebrown: "#8b4513",
123
- salmon: "#fa8072",
124
- sandybrown: "#f4a460",
125
- seagreen: "#2e8b57",
126
- seashell: "#fff5ee",
127
- sienna: "#a0522d",
128
- silver: "#c0c0c0",
129
- skyblue: "#87ceeb",
130
- slateblue: "#6a5acd",
131
- slategray: "#708090",
132
- snow: "#fffafa",
133
- springgreen: "#00ff7f",
134
- steelblue: "#4682b4",
135
- tan: "#d2b48c",
136
- teal: "#008080",
137
- thistle: "#d8bfd8",
138
- tomato: "#ff6347",
139
- turquoise: "#40e0d0",
140
- violet: "#ee82ee",
141
- wheat: "#f5deb3",
142
- white: "#ffffff",
143
- whitesmoke: "#f5f5f5",
144
- yellow: "#ffff00",
145
- yellowgreen: "#9acd32",
146
- transparent: "rgba(0,0,0,0)"
147
- };
148
-
149
- /**
150
- * 画图基础对象
151
- * 当前库的工具类
152
- *
153
- * @class jmUtils
154
- * @static
155
- */
156
- export default class jmUtils {
157
- /**
158
- * 复制一个对象
159
- *
160
- * @method clone
161
- * @static
162
- * @param {object} source 被复制的对象
163
- * @param {object} target 可选,如果指定就表示复制给这个对象,如果为boolean它就是deep参数
164
- * @param {boolean} deep 是否深度复制,如果为true,数组内的每个对象都会被复制
165
- * @param {function} copyHandler 复制对象回调,如果返回undefined,就走后面的逻辑,否则到这里中止
166
- * @return {object} 参数source的拷贝对象
167
- */
168
- static clone(source, target, deep = false, copyHandler = null, deepIndex = 0) {
169
- // 如果有指定回调,则用回调处理,否则走后面的复制逻辑
170
- if(typeof copyHandler === 'function') {
171
- const obj = copyHandler(source, deep, deepIndex);
172
- if(obj) return obj;
173
- }
174
- deepIndex++; // 每执行一次,需要判断最大拷贝深度
175
-
176
- if(typeof target === 'boolean') {
177
- deep = target;
178
- target = undefined;
179
- }
180
-
181
- // 超过100拷贝深度,直接返回
182
- if(deepIndex > 100) {
183
- return target;
184
- }
185
-
186
- if(source && typeof source === 'object') {
187
- target = target || {};
188
-
189
- //如果为当前泛型,则直接new
190
- if(this.isType(source, jmList)) {
191
- return new jmList(source);
192
- }
193
- else if(Array.isArray(source)) {
194
- //如果是深度复,则拷贝每个对象
195
- if(deep) {
196
- let dest = [];
197
- for(let i=0; i<source.length; i++) {
198
- dest.push(this.clone(source[i], target[i], deep, copyHandler, deepIndex));
199
- }
200
- return dest;
201
- }
202
- return source.slice(0);
203
- }
204
-
205
- if(source.__proto__) target.__proto__ = source.__proto__;
206
-
207
- for(let k in source) {
208
- if(k === 'constructor') continue;
209
- const v = source[k];
210
- // 不复制页面元素和class对象
211
- if(v && (v.tagName || v.getContext)) {
212
- target[k] = v;
213
- continue;
214
- }
215
-
216
- // 如果不是对象和空,则采用target的属性
217
- if(typeof target[k] === 'object' || typeof target[k] === 'undefined') {
218
- target[k] = this.clone(v, target[k], deep, copyHandler, deepIndex);
219
- }
220
- }
221
- return target;
222
- }
223
- else if(typeof target != 'undefined') {
224
- return target;
225
- }
226
-
227
- return source;
228
- }
229
-
230
- /**
231
- * 绑定事件到html对象
232
- *
233
- * @method bindEvent
234
- * @static
235
- * @param {element} html元素对象
236
- * @param {string} name 事件名称
237
- * @param {function} fun 事件委托
238
- * @returns {name, fun, target} 返回当前绑定
239
- */
240
- static bindEvent(target, name, fun, opt) {
241
- if(name && name.indexOf && name.indexOf(' ') != -1) {
242
- let ns = name.split(' ');
243
- for(let i=0;i<ns.length;i++) {
244
- this.bindEvent(target, ns[i], fun, opt);
245
- }
246
- }
247
- if(target.attachEvent) {
248
- target.attachEvent("on"+name, fun, opt);
249
- }
250
- else if(target.addEventListener) {
251
- target.addEventListener(name, fun, opt);
252
- }
253
- return {
254
- name,
255
- target,
256
- fun
257
- };
258
- }
259
-
260
- /**
261
- * 从对象中移除事件到
262
- *
263
- * @method removeEvent
264
- * @static
265
- * @param {element} html元素对象
266
- * @param {string} name 事件名称
267
- * @param {function} fun 事件委托
268
- */
269
- static removeEvent(target, name, fun) {
270
- if(target.removeEventListener) {
271
- return target.removeEventListener(name, fun, false);
272
- }
273
- else if(target.detachEvent) {
274
- target.detachEvent('on' + name, fun);
275
- return true;
276
- }
277
- else {
278
- target['on' + name] = null;
279
- }
280
- }
281
-
282
- /**
283
- * 获取元素的绝对定位
284
- *
285
- * @method getElementPosition
286
- * @static
287
- * @param {element} el 目标元素对象
288
- * @return {position} 位置对象(top,left)
289
- */
290
- static getElementPosition(el) {
291
- let pos = {"top": 0, "left": 0};
292
- if(!el) return pos;
293
-
294
- if (el.offsetParent) {
295
- while (el.offsetParent) {
296
- pos.top += el.offsetTop;
297
- pos.left += el.offsetLeft;
298
- el = el.offsetParent;
299
- }
300
- }
301
- else if(el.x) {
302
- pos.left += el.x;
303
- }
304
- else if(el.x){
305
- pos.top += el.y;
306
- }
307
- return pos;
308
- }
309
- /**
310
- * 获取元素事件触发的位置
311
- *
312
- * @method getEventPosition
313
- * @static
314
- * @param {eventArg} evt 当前触发事件的参数
315
- * @param {point} [scale] 当前画布的缩放比例
316
- * @return {point} 事件触发的位置
317
- */
318
- static getEventPosition (evt, scale) {
319
- evt = evt || event;
320
- const isWXMiniApp = evt.isWXMiniApp;
321
- let isTouch = false;
322
- let touches = evt.changedTouches || evt.targetTouches || evt.touches;
323
- let target = evt.target || evt.srcElement;
324
- if(touches && touches.length) {
325
- evt = touches[0];//兼容touch事件
326
- if(!evt.target) evt.target = target;
327
- isTouch = true;
328
- }
329
- let px = evt.pageX || evt.x;
330
- if(typeof px == 'undefined') px = evt.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
331
- let py = evt.pageY || evt.y;
332
- if(typeof py == 'undefined') py = evt.clientY + (document.documentElement.scrollTop || document.body.scrollTop);
333
-
334
- let ox = evt.offsetX;
335
- let oy = evt.offsetY;
336
- if(typeof ox === 'undefined' && typeof oy === 'undefined') {
337
- // 小程序下取x,y就是它的相对坐标
338
- if(isWXMiniApp) {
339
- ox = evt.x;
340
- oy = evt.y;
341
- }
342
- else {
343
- let p = this.getElementPosition(target);
344
- ox= px - p.left;
345
- oy = py - p.top;
346
- }
347
- }
348
- if(scale) {
349
- if(scale.x) ox = ox / scale.x;
350
- if(scale.y) oy = oy / scale.y;
351
- }
352
-
353
- return {
354
- pageX: px,
355
- pageY: py,
356
- clientX: evt.clientX,
357
- clientY: evt.clientY,
358
- //相对于容器偏移量
359
- offsetX: ox,
360
- offsetY: oy,
361
- layerX: evt.layerX,
362
- layerY: evt.layerY,
363
- screenX: evt.screenX,
364
- screenY: evt.screenY,
365
- x: ox,
366
- y: oy,
367
- isTouch: isTouch,
368
- touches,
369
- isWXMiniApp
370
- };
371
- }
372
-
373
- /**
374
- * 检 查对象是否为指定的类型,不包括继承
375
- *
376
- * @method isType
377
- * @static
378
- * @param {object} target 需要判断类型的对象
379
- * @param {class} type 对象类型
380
- * @return {boolean} 返回对象是否为指定类型
381
- */
382
- static isType(target, type) {
383
- if(!target || typeof target !== 'object') return false;
384
- if(target.constructor === type) return true;
385
- /*if(target.__baseType) {
386
- return jmUtils.isType(target.__baseType.prototype,type);
387
- }*/
388
-
389
- //return target instanceof type;
390
- return false;
391
- }
392
- /**
393
- * 判断点是否在多边形内
394
- * 如果一个点在多边形内部,任意角度做射线肯定会与多边形要么有一个交点,要么有与多边形边界线重叠。
395
- * 如果一个点在多边形外部,任意角度做射线要么与多边形有一个交点,要么有两个交点,要么没有交点,要么有与多边形边界线重叠。
396
- * 利用上面的结论,我们只要判断这个点与多边形的交点个数,就可以判断出点与多边形的位置关系了。
397
- *
398
- * @method pointInPolygon
399
- * @static
400
- * @param {point} pt 坐标对象
401
- * @param {array} polygon 多边型角坐标对象数组
402
- * @param {number} offset 判断可偏移值
403
- * @return {integer} 0= 不在图形内和线上,1=在边上,2=在图形内部
404
- */
405
- static pointInPolygon(pt, polygon, offset) {
406
- offset = offset || 1;
407
- offset = offset / 2;
408
- let i, j, n = polygon.length;
409
- let inside = false, redo = true;
410
-
411
- if(!polygon || n == 0) return 0;
412
- if(n == 1) {
413
- return Math.abs(polygon[0].x - pt.x) <= offset && Math.abs(polygon[0].y - pt.y) <= offset;
414
- }
415
-
416
- //一条直线
417
- else if(n == 2) {
418
- //在最左边之外或在最右边之外
419
- if(Math.min(polygon[0].x,polygon[1].x) - pt.x > offset ||
420
- pt.x - Math.max(polygon[0].x,polygon[1].x) > offset ) {
421
- return 0;
422
- }
423
- //在最顶部之外或在最底部之外
424
- if(Math.min(polygon[0].y,polygon[1].y) - pt.y > offset ||
425
- pt.y - Math.max(polygon[0].y,polygon[1].y) > offset) {
426
- return 0;
427
- }
428
-
429
- //如果线为平行为纵坐标。
430
- if(polygon[0].x == polygon[1].x){
431
- return (Math.abs(polygon[0].x - pt.x) <= offset && (pt.y - polygon[0].y) * (pt.y - polygon[1].y) <= 0)? 1:0;
432
- }
433
- //如果线为平行为横坐标。
434
- if(polygon[0].y == polygon[1].y){
435
- return (Math.abs(polygon[0].y - pt.y) <= offset && (pt.x - polygon[0].x) * (pt.x - polygon[1].x) <= 0)? 1:0;
436
- }
437
-
438
- if(Math.abs(polygon[0].x - pt.x) < offset && Math.abs(polygon[0].y - pt.y) < offset) {
439
- return 1;
440
- }
441
- if(Math.abs(polygon[1].x - pt.x) < offset && Math.abs(polygon[1].y - pt.y) < offset) {
442
- return 1;
443
- }
444
-
445
- //点到直线的距离小于宽度的一半,表示在线上
446
- if(pt.y != polygon[0].y && pt.y != polygon[1].y) {
447
-
448
- let f = (polygon[1].x - polygon[0].x) / (polygon[1].y - polygon[0].y) * (pt.y - polygon[0].y);
449
- let ff = (pt.y - polygon[0].y) / Math.sqrt(f * f + (pt.y - polygon[0].y) * (pt.y - polygon[0].y));
450
- let l = ff * (pt.x - polygon[0].x - f );
451
-
452
- return Math.abs(l) <= offset ?1:0;
453
- }
454
- return 0;
455
- }
456
-
457
- for (i = 0;i < n;++i) {
458
- if (polygon[i].x == pt.x && // 是否在顶点上
459
- polygon[i].y == pt.y ) {
460
- return 1;
461
- }
462
- }
463
-
464
- //pt = this.clone(pt);
465
- while (redo) {
466
- redo = false;
467
- inside = false;
468
- for (i = 0,j = n - 1;i < n;j = i++) {
469
- if ( (polygon[i].y < pt.y && pt.y < polygon[j].y) ||
470
- (polygon[j].y < pt.y && pt.y < polygon[i].y) ) {
471
- if (pt.x <= polygon[i].x || pt.x <= polygon[j].x) {
472
- var _x = (pt.y-polygon[i].y)*(polygon[j].x-polygon[i].x)/(polygon[j].y-polygon[i].y)+polygon[i].x;
473
- if (pt.x < _x) // 在线的左侧
474
- inside = !inside;
475
- else if (pt.x == _x) // 在线上
476
- {
477
- return 1;
478
- }
479
- }
480
- }
481
- else if ( pt.y == polygon[i].y) {
482
- if (pt.x < polygon[i].x) { // 交点在顶点上
483
- if(polygon[i].y > polygon[j].y) {
484
- --pt.y
485
- }
486
- else {
487
- ++pt.y;
488
- }
489
- redo = true;
490
- break;
491
- }
492
- }
493
- else if ( polygon[i].y == polygon[j].y && // 在水平的边界线上
494
- pt.y == polygon[i].y &&
495
- ( (polygon[i].x < pt.x && pt.x < polygon[j].x) ||
496
- (polygon[j].x < pt.x && pt.x < polygon[i].x) ) ) {
497
- inside = true;
498
- break;
499
- }
500
- }
501
- }
502
-
503
- return inside ? 2:0;
504
- }
505
-
506
- /**
507
- * @method judge 判断点是否在多边形中
508
- * @param {point} dot {{x,y}} 需要判断的点
509
- * @param {array} coordinates {{x,y}} 多边形点坐标的数组,为保证图形能够闭合,起点和终点必须相等。
510
- * 比如三角形需要四个点表示,第一个点和最后一个点必须相同。
511
- * @param {number} 是否为实心 1=
512
- * @returns {boolean} 结果 true=在形状内
513
- */
514
- /*static judge(dot,coordinates,noneZeroMode) {
515
- // 默认启动none zero mode
516
- noneZeroMode=noneZeroMode||1;
517
- var x = dot.x,y=dot.y;
518
- var crossNum = 0;
519
- // 点在线段的左侧数目
520
- var leftCount = 0;
521
- // 点在线段的右侧数目
522
- var rightCount = 0;
523
- for(var i=0;i<coordinates.length-1;i++){
524
- var start = coordinates[i];
525
- var end = coordinates[i+1];
526
-
527
- // 起点、终点斜率不存在的情况
528
- if(start.x===end.x) {
529
- // 因为射线向右水平,此处说明不相交
530
- if(x>start.x) continue;
531
-
532
- // 从左侧贯穿
533
- if((end.y>start.y&&y>=start.y && y<=end.y)){
534
- leftCount++;
535
- crossNum++;
536
- }
537
- // 从右侧贯穿
538
- if((end.y<start.y&&y>=end.y && y<=start.y)) {
539
- rightCount++;
540
- crossNum++;
541
- }
542
- continue;
543
- }
544
- // 斜率存在的情况,计算斜率
545
- var k=(end.y-start.y)/(end.x-start.x);
546
- // 交点的x坐标
547
- var x0 = (y-start.y)/k+start.x;
548
- // 因为射线向右水平,此处说明不相交
549
- if(x>x0) continue;
550
-
551
- if((end.x>start.x&&x0>=start.x && x0<=end.x)){
552
- crossNum++;
553
- if(k>=0) leftCount++;
554
- else rightCount++;
555
- }
556
- if((end.x<start.x&&x0>=end.x && x0<=start.x)) {
557
- crossNum++;
558
- if(k>=0) rightCount++;
559
- else leftCount++;
560
- }
561
- }
562
-
563
- return noneZeroMode===1?leftCount-rightCount!==0:crossNum%2===1;
564
- }*/
565
-
566
- /**
567
- * 检查边界,子对象是否超出父容器边界
568
- * 当对象偏移offset后是否出界
569
- * 返回(left:0,right:0,top:0,bottom:0)
570
- * 如果right>0表示右边出界right偏移量,left<0则表示左边出界left偏移量
571
- * 如果bottom>0表示下边出界bottom偏移量,top<0则表示上边出界ltop偏移量
572
- *
573
- * @method checkOutSide
574
- * @static
575
- * @param {bound} parentBounds 父对象的边界
576
- * @param {bound} targetBounds 对象的边界
577
- * @param {number} offset 判断是否越界可容偏差
578
- * @return {bound} 越界标识
579
- */
580
- static checkOutSide(parentBounds, targetBounds, offset) {
581
- let result = {left:0,right:0,top:0,bottom:0};
582
- if(offset.x < 0 ) {
583
- result.left = targetBounds.left + offset.x - parentBounds.left;
584
- }
585
- else if(offset.x > 0 ) {
586
- result.right = targetBounds.right + offset.x - parentBounds.right;
587
- }
588
-
589
- if(offset.y < 0 ) {
590
- result.top = targetBounds.top + offset.y - parentBounds.top;
591
- }
592
- else if(offset.y > 0) {
593
- result.bottom = targetBounds.bottom + offset.y - parentBounds.bottom;
594
- }
595
- return result;
596
- }
597
-
598
- /**
599
- * 把一个或多个点绕某个点旋转一定角度
600
- * 先把坐标原点移到旋转中心点,计算后移回
601
- * @method rotatePoints
602
- * @static
603
- * @param {Array/object} p 一个或多个点
604
- * @param {*} rp 旋转中心点
605
- * @param {*} r 旋转角度
606
- */
607
- static rotatePoints(p, rp, r) {
608
- if(!r || !p) return p;
609
- let cos = Math.cos(r);
610
- let sin = Math.sin(r);
611
- if(Array.isArray(p)) {
612
- for(let i=0;i<p.length;i++) {
613
- if(!p[i]) continue;
614
- let x1 = p[i].x - rp.x;
615
- let y1 = p[i].y - rp.y;
616
- p[i].x = x1 * cos - y1 * sin + rp.x;
617
- p[i].y = x1 * sin + y1 * cos + rp.y;
618
- }
619
- }
620
- else {
621
- let x1 = p.x - rp.x;
622
- let y1 = p.y - rp.y;
623
- p.x = x1 * cos - y1 * sin + rp.x;
624
- p.y = x1 * sin + y1 * cos + rp.y;
625
- }
626
- return p;
627
- }
628
-
629
- /**
630
- * 去除字符串开始字符
631
- *
632
- * @method trimStart
633
- * @static
634
- * @param {string} source 需要处理的字符串
635
- * @param {char} [c] 要去除字符串的前置字符
636
- * @return {string} 去除前置字符后的字符串
637
- */
638
- static trimStart(source, c) {
639
- c = c || ' ';
640
- if(source && source.length > 0) {
641
- let sc = source[0];
642
- if(sc === c || c.indexOf(sc) >= 0) {
643
- source = source.substring(1);
644
- return this.trimStart(source,c);
645
- }
646
- }
647
- return source;
648
- }
649
-
650
- /**
651
- * 去除字符串结束的字符c
652
- *
653
- * @method trimEnd
654
- * @static
655
- * @param {string} source 需要处理的字符串
656
- * @param {char} [c] 要去除字符串的后置字符
657
- * @return {string} 去除后置字符后的字符串
658
- */
659
- static trimEnd(source, c) {
660
- c = c || ' ';
661
- if(source && source.length > 0) {
662
- let sc = source[source.length - 1];
663
- if(sc === c || c.indexOf(sc) >= 0) {
664
- source = source.substring(0,source.length - 1);
665
- return this.trimStart(source,c);
666
- }
667
- }
668
- return source;
669
- }
670
-
671
- /**
672
- * 去除字符串开始与结束的字符
673
- *
674
- * @method trim
675
- * @static
676
- * @param {string} source 需要处理的字符串
677
- * @param {char} [c] 要去除字符串的字符
678
- * @return {string} 去除字符后的字符串
679
- */
680
- static trim(source,c) {
681
- return this.trimEnd(this.trimStart(source,c),c);
682
- }
683
-
684
- /**
685
- * 检查是否为百分比参数
686
- *
687
- * @method checkPercent
688
- * @static
689
- * @param {string} 字符串参数
690
- * @return {boolean} true=当前字符串为百分比参数,false=不是
691
- */
692
- static checkPercent(per) {
693
- if(typeof per === 'string') {
694
- per = this.trim(per);
695
- if(per[per.length - 1] == '%') {
696
- return per;
697
- }
698
- }
699
- }
700
-
701
- /**
702
- * 转换百分数为数值类型
703
- *
704
- * @method percentToNumber
705
- * @static
706
- * @param {string} per 把百分比转为数值的参数
707
- * @return {number} 百分比对应的数值
708
- */
709
- static percentToNumber(per) {
710
- if(typeof per === 'string') {
711
- let tmp = this.checkPercent(per);
712
- if(tmp) {
713
- per = this.trim(tmp,'% ');
714
- per = per / 100;
715
- }
716
- }
717
- return per;
718
- }
719
-
720
- /**
721
- * 转换16进制为数值
722
- *
723
- * @method hexToNumber
724
- * @static
725
- * @param {string} h 16进制颜色表达
726
- * @return {number} 10进制表达
727
- */
728
- static hexToNumber(h) {
729
- if(typeof h !== 'string') return h;
730
-
731
- h = h.toLowerCase();
732
- let hex = '0123456789abcdef';
733
- let v = 0;
734
- let l = h.length;
735
- for(let i=0;i<l;i++) {
736
- let iv = hex.indexOf(h[i]);
737
- if(iv == 0) continue;
738
-
739
- for(let j=1;j<l - i;j++) {
740
- iv *= 16;
741
- }
742
- v += iv;
743
- }
744
- return v;
745
- }
746
-
747
- /**
748
- * 转换数值为16进制字符串表达
749
- *
750
- * @method hex
751
- * @static
752
- * @param {number} v 数值
753
- * @return {string} 16进制表达
754
- */
755
- static numberToHex(v) {
756
- let hex = '0123456789abcdef';
757
-
758
- let h = '';
759
- while(v > 0) {
760
- let t = v % 16;
761
- h = hex[t] + h;
762
- v = Math.floor(v / 16);
763
- }
764
- return h;
765
- }
766
-
767
- /**
768
- * 16进制颜色转为r g b a 对象 {r, g , b, a}
769
- * @param {string}} hex 16进度的颜色
770
- */
771
- static hexToRGBA(hex) {
772
- if(typeof hex === 'string') hex = this.trim(hex);
773
- else return hex;
774
-
775
- // 如果缓存存在,则直接返回
776
- this.__hexToRGBA_Cache = this.__hexToRGBA_Cache || {};
777
- if(this.__hexToRGBA_Cache[hex]) return this.__hexToRGBA_Cache[hex];
778
-
779
- let res = hex;
780
-
781
- // 系统颜色
782
- if(colorKeywords[res]) res = colorKeywords[res];
783
-
784
- //当为7位时,表示需要转为带透明度的rgba
785
- if(res[0] == '#') {
786
- const color = {
787
- a: 1
788
- };
789
- if(res.length >= 8) {
790
- color.a = res.substr(1,2);
791
- color.g = res.substr(5,2);
792
- color.b = res.substr(7,2);
793
- color.r = res.substr(3,2);
794
- //透明度
795
- color.a = Number((this.hexToNumber(color.a) / 255).toFixed(4));
796
-
797
- color.r = this.hexToNumber(color.r||0);
798
- color.g = this.hexToNumber(color.g||0);
799
- color.b = this.hexToNumber(color.b||0);
800
- res = color;
801
- }
802
- // #cccccc || #ccc
803
- else if(res.length === 7 || res.length === 4) {
804
- // #ccc这种情况,把每个位复制一份
805
- if(res.length === 4) {
806
- color.g = res.substr(2, 1);
807
- color.g = color.g + color.g;
808
- color.b = res.substr(3, 1);
809
- color.b = color.b + color.b;
810
- color.r = res.substr(1, 1);
811
- color.r = color.r + color.r;
812
- }
813
- else {
814
- color.g = res.substr(3, 2);//除#号外的第二位
815
- color.b = res.substr(5, 2);
816
- color.r = res.substr(1, 2);
817
- }
818
-
819
- color.r = this.hexToNumber(color.r||0);
820
- color.g = this.hexToNumber(color.g||0);
821
- color.b = this.hexToNumber(color.b||0);
822
-
823
- res = color;
824
- }
825
- //如果是5位的话,# 则第2位表示A,后面依次是r,g,b
826
- else if(res.length === 5) {
827
- color.a = res.substr(1,1);
828
- color.g = res.substr(3,1);//除#号外的第二位
829
- color.b = res.substr(4,1);
830
- color.r = res.substr(2,1);
831
-
832
- color.r = this.hexToNumber(color.r||0);
833
- color.g = this.hexToNumber(color.g||0);
834
- color.b = this.hexToNumber(color.b||0);
835
- //透明度
836
- color.a = Number((this.hexToNumber(color.a) / 255).toFixed(4));
837
- res = color;
838
- }
839
- }
840
- if(typeof res === 'string') {
841
- const m = res.match(/rgb(a)?\s*\(\s*([\d\.]+)\s*,\s*([\d\.]+)\s*,\s*([\d\.]+)\s*(,\s*[\d\.]+)?\s*\)/i);
842
- if(m && m.length === 6) {
843
- const color = {
844
- r: Number(m[2]),
845
- g: Number(m[3]),
846
- b: Number(m[4]),
847
- a: Number(this.trimStart(m[5]||'1', ','))
848
- };
849
- res = color;
850
- }
851
- }
852
- return this.__hexToRGBA_Cache[hex] = res;
853
- }
854
-
855
- /**
856
- * 255的rgb值转为0-1的值
857
- * @param {rgba} color 颜色
858
- */
859
- static rgbToDecimal(color) {
860
- color = this.clone(color);
861
- color.r = this.byteToDecimal(color.r);
862
- color.g = this.byteToDecimal(color.g);
863
- color.b = this.byteToDecimal(color.b);
864
- return color;
865
- }
866
-
867
- //255值转为0-1的小数
868
- static byteToDecimal(b) {
869
- return b / 255;
870
- }
871
-
872
- /**
873
- * 转换颜色格式,如果输入r,g,b则转为hex格式,如果为hex则转为r,g,b格式
874
- *
875
- * @method toColor
876
- * @static
877
- * @param {string} hex 16进制颜色表达
878
- * @return {string} 颜色字符串
879
- */
880
- static toColor(r, g, b, a) {
881
- if(typeof r === 'string' && r) {
882
- r = this.trim(r);
883
- // 正常的颜色表达,不需要转换
884
- if(r[0] === '#' && (r.length === 4 || r.length === 7)) return r;
885
-
886
- const color = this.hexToRGBA(r);
887
- if(typeof color === 'string') return color;
888
-
889
- r = typeof color.r !== 'undefined'? color.r: r;
890
- g = typeof color.g !== 'undefined'? color.g: g;
891
- b = typeof color.b !== 'undefined'? color.b: b;
892
- a = typeof color.a !== 'undefined'? color.a: a;
893
- }
894
- if(r && typeof r === 'object') {
895
- g = r.g;
896
- b = r.b;
897
- a = r.a || 1;
898
- r = r.r;
899
- }
900
- if(typeof r != 'undefined' && typeof g != 'undefined' && typeof b != 'undefined') {
901
- if(typeof a != 'undefined') {
902
- return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
903
- }
904
- else {
905
- return 'rgb(' + r + ',' + g + ',' + b + ')';
906
- }
907
- }
908
- return r;
909
- }
910
- // window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
911
- static requestAnimationFrame(callback, win) {
912
- let fun = win && win.requestAnimationFrame? win.requestAnimationFrame: (typeof window !== 'undefined' && window.requestAnimationFrame? window.requestAnimationFrame: setTimeout);
913
- return fun(callback, 20);
914
- }
915
- static cancelAnimationFrame(handler, win) {
916
- let fun = win && win.cancelAnimationFrame? win.cancelAnimationFrame: (typeof window !== 'undefined' && window.cancelAnimationFrame? window.cancelAnimationFrame: clearTimeout);
917
- return fun(handler);
918
- }
919
- }
1
+
2
+ import { jmList } from './jmList.js';
3
+
4
+ const colorKeywords = {
5
+ aliceblue: "#f0f8ff",
6
+ antiquewhite: "#faebd7",
7
+ aqua: "#00ffff",
8
+ aquamarine: "#7fffd4",
9
+ azure: "#f0ffff",
10
+ beige: "#f5f5dc",
11
+ bisque: "#ffe4c4",
12
+ black: "#000000",
13
+ blanchedalmond: "#ffebcd",
14
+ blue: "#0000ff",
15
+ blueviolet: "#8a2be2",
16
+ brown: "#a52a2a",
17
+ burlywood: "#deb887",
18
+ cadetblue: "#5f9ea0",
19
+ chartreuse: "#7fff00",
20
+ chocolate: "#d2691e",
21
+ coral: "#ff7f50",
22
+ cornflowerblue: "#6495ed",
23
+ cornsilk: "#fff8dc",
24
+ crimson: "#dc143c",
25
+ cyan: "#00ffff",
26
+ darkblue: "#00008b",
27
+ darkcyan: "#008b8b",
28
+ darkgoldenrod: "#b8860b",
29
+ darkgray: "#a9a9a9",
30
+ darkgreen: "#006400",
31
+ darkkhaki: "#bdb76b",
32
+ darkmagenta: "#8b008b",
33
+ darkolivegreen: "#556b2f",
34
+ darkorange: "#ff8c00",
35
+ darkorchid: "#9932cc",
36
+ darkred: "#8b0000",
37
+ darksalmon: "#e9967a",
38
+ darkseagreen: "#8fbc8f",
39
+ darkslateblue: "#483d8b",
40
+ darkslategray: "#2f4f4f",
41
+ darkturquoise: "#00ced1",
42
+ darkviolet: "#9400d3",
43
+ deeppink: "#ff1493",
44
+ deepskyblue: "#00bfff",
45
+ dimgray: "#696969",
46
+ dodgerblue: "#1e90ff",
47
+ firebrick: "#b22222",
48
+ floralwhite: "#fffaf0",
49
+ forestgreen: "#228b22",
50
+ fuchsia: "#ff00ff",
51
+ gainsboro: "#dcdcdc",
52
+ ghostwhite: "#f8f8ff",
53
+ gold: "#ffd700",
54
+ goldenrod: "#daa520",
55
+ gray: "#808080",
56
+ green: "#008000",
57
+ greenyellow: "#adff2f",
58
+ grey: "#808080",
59
+ honeydew: "#f0fff0",
60
+ hotpink: "#ff69b4",
61
+ indianred: "#cd5c5c",
62
+ indigo: "#4b0082",
63
+ ivory: "#fffff0",
64
+ khaki: "#f0e68c",
65
+ lavender: "#e6e6fa",
66
+ lavenderblush: "#fff0f5",
67
+ lawngreen: "#7cfc00",
68
+ lemonchiffon: "#fffacd",
69
+ lightblue: "#add8e6",
70
+ lightcoral: "#f08080",
71
+ lightcyan: "#e0ffff",
72
+ lightgoldenrodyellow: "#fafad2",
73
+ lightgrey: "#d3d3d3",
74
+ lightgreen: "#90ee90",
75
+ lightpink: "#ffb6c1",
76
+ lightsalmon: "#ffa07a",
77
+ lightseagreen: "#20b2aa",
78
+ lightskyblue: "#87cefa",
79
+ lightslategray: "#778899",
80
+ lightsteelblue: "#b0c4de",
81
+ lightyellow: "#ffffe0",
82
+ lime: "#00ff00",
83
+ limegreen: "#32cd32",
84
+ linen: "#faf0e6",
85
+ magenta: "#ff00ff",
86
+ maroon: "#800000",
87
+ mediumaquamarine: "#66cdaa",
88
+ mediumblue: "#0000cd",
89
+ mediumorchid: "#ba55d3",
90
+ mediumpurple: "#9370d8",
91
+ mediumseagreen: "#3cb371",
92
+ mediumslateblue: "#7b68ee",
93
+ mediumspringgreen: "#00fa9a",
94
+ mediumturquoise: "#48d1cc",
95
+ mediumvioletred: "#c71585",
96
+ midnightblue: "#191970",
97
+ mintcream: "#f5fffa",
98
+ mistyrose: "#ffe4e1",
99
+ moccasin: "#ffe4b5",
100
+ navajowhite: "#ffdead",
101
+ navy: "#000080",
102
+ oldlace: "#fdf5e6",
103
+ olive: "#808000",
104
+ olivedrab: "#6b8e23",
105
+ orange: "#ffa500",
106
+ orangered: "#ff4500",
107
+ orchid: "#da70d6",
108
+ palegoldenrod: "#eee8aa",
109
+ palegreen: "#98fb98",
110
+ paleturquoise: "#afeeee",
111
+ palevioletred: "#d87093",
112
+ papayawhip: "#ffefd5",
113
+ peachpuff: "#ffdab9",
114
+ peru: "#cd853f",
115
+ pink: "#ffc0cb",
116
+ plum: "#dda0dd",
117
+ powderblue: "#b0e0e6",
118
+ purple: "#800080",
119
+ red: "#ff0000",
120
+ rosybrown: "#bc8f8f",
121
+ royalblue: "#4169e1",
122
+ saddlebrown: "#8b4513",
123
+ salmon: "#fa8072",
124
+ sandybrown: "#f4a460",
125
+ seagreen: "#2e8b57",
126
+ seashell: "#fff5ee",
127
+ sienna: "#a0522d",
128
+ silver: "#c0c0c0",
129
+ skyblue: "#87ceeb",
130
+ slateblue: "#6a5acd",
131
+ slategray: "#708090",
132
+ snow: "#fffafa",
133
+ springgreen: "#00ff7f",
134
+ steelblue: "#4682b4",
135
+ tan: "#d2b48c",
136
+ teal: "#008080",
137
+ thistle: "#d8bfd8",
138
+ tomato: "#ff6347",
139
+ turquoise: "#40e0d0",
140
+ violet: "#ee82ee",
141
+ wheat: "#f5deb3",
142
+ white: "#ffffff",
143
+ whitesmoke: "#f5f5f5",
144
+ yellow: "#ffff00",
145
+ yellowgreen: "#9acd32",
146
+ transparent: "rgba(0,0,0,0)"
147
+ };
148
+
149
+ /**
150
+ * 画图基础对象
151
+ * 当前库的工具类
152
+ *
153
+ * @class jmUtils
154
+ * @static
155
+ */
156
+ export default class jmUtils {
157
+ /**
158
+ * 复制一个对象
159
+ *
160
+ * @method clone
161
+ * @static
162
+ * @param {object} source 被复制的对象
163
+ * @param {object} target 可选,如果指定就表示复制给这个对象,如果为boolean它就是deep参数
164
+ * @param {boolean} deep 是否深度复制,如果为true,数组内的每个对象都会被复制
165
+ * @param {function} copyHandler 复制对象回调,如果返回undefined,就走后面的逻辑,否则到这里中止
166
+ * @return {object} 参数source的拷贝对象
167
+ */
168
+ static clone(source, target, deep = false, copyHandler = null, deepIndex = 0) {
169
+ // 如果有指定回调,则用回调处理,否则走后面的复制逻辑
170
+ if(typeof copyHandler === 'function') {
171
+ const obj = copyHandler(source, deep, deepIndex);
172
+ if(obj) return obj;
173
+ }
174
+ deepIndex++; // 每执行一次,需要判断最大拷贝深度
175
+
176
+ if(typeof target === 'boolean') {
177
+ deep = target;
178
+ target = undefined;
179
+ }
180
+
181
+ // 超过100拷贝深度,直接返回
182
+ if(deepIndex > 100) {
183
+ return target;
184
+ }
185
+
186
+ if(source && typeof source === 'object') {
187
+ target = target || {};
188
+
189
+ //如果为当前泛型,则直接new
190
+ if(this.isType(source, jmList)) {
191
+ return new jmList(source);
192
+ }
193
+ else if(Array.isArray(source)) {
194
+ //如果是深度复,则拷贝每个对象
195
+ if(deep) {
196
+ let dest = [];
197
+ for(let i=0; i<source.length; i++) {
198
+ dest.push(this.clone(source[i], target[i], deep, copyHandler, deepIndex));
199
+ }
200
+ return dest;
201
+ }
202
+ return source.slice(0);
203
+ }
204
+
205
+ if(source.__proto__) target.__proto__ = source.__proto__;
206
+
207
+ for(let k in source) {
208
+ if(k === 'constructor') continue;
209
+ const v = source[k];
210
+ // 不复制页面元素和class对象
211
+ if(v && (v.tagName || v.getContext)) {
212
+ target[k] = v;
213
+ continue;
214
+ }
215
+
216
+ // 如果不是对象和空,则采用target的属性
217
+ if(typeof target[k] === 'object' || typeof target[k] === 'undefined') {
218
+ target[k] = this.clone(v, target[k], deep, copyHandler, deepIndex);
219
+ }
220
+ }
221
+ return target;
222
+ }
223
+ else if(typeof target != 'undefined') {
224
+ return target;
225
+ }
226
+
227
+ return source;
228
+ }
229
+
230
+ /**
231
+ * 绑定事件到html对象
232
+ *
233
+ * @method bindEvent
234
+ * @static
235
+ * @param {element} html元素对象
236
+ * @param {string} name 事件名称
237
+ * @param {function} fun 事件委托
238
+ * @returns {name, fun, target} 返回当前绑定
239
+ */
240
+ static bindEvent(target, name, fun, opt) {
241
+ if(name && name.indexOf && name.indexOf(' ') != -1) {
242
+ let ns = name.split(' ');
243
+ for(let i=0;i<ns.length;i++) {
244
+ this.bindEvent(target, ns[i], fun, opt);
245
+ }
246
+ }
247
+ if(target.attachEvent) {
248
+ target.attachEvent("on"+name, fun, opt);
249
+ }
250
+ else if(target.addEventListener) {
251
+ target.addEventListener(name, fun, opt);
252
+ }
253
+ return {
254
+ name,
255
+ target,
256
+ fun
257
+ };
258
+ }
259
+
260
+ /**
261
+ * 从对象中移除事件到
262
+ *
263
+ * @method removeEvent
264
+ * @static
265
+ * @param {element} html元素对象
266
+ * @param {string} name 事件名称
267
+ * @param {function} fun 事件委托
268
+ */
269
+ static removeEvent(target, name, fun) {
270
+ if(target.removeEventListener) {
271
+ return target.removeEventListener(name, fun, false);
272
+ }
273
+ else if(target.detachEvent) {
274
+ target.detachEvent('on' + name, fun);
275
+ return true;
276
+ }
277
+ else {
278
+ target['on' + name] = null;
279
+ }
280
+ }
281
+
282
+ /**
283
+ * 获取元素的绝对定位
284
+ *
285
+ * @method getElementPosition
286
+ * @static
287
+ * @param {element} el 目标元素对象
288
+ * @return {position} 位置对象(top,left)
289
+ */
290
+ static getElementPosition(el) {
291
+ let pos = {"top": 0, "left": 0};
292
+ if(!el) return pos;
293
+
294
+ if (el.offsetParent) {
295
+ while (el.offsetParent) {
296
+ pos.top += el.offsetTop;
297
+ pos.left += el.offsetLeft;
298
+ el = el.offsetParent;
299
+ }
300
+ }
301
+ else if(el.x) {
302
+ pos.left += el.x;
303
+ }
304
+ else if(el.x){
305
+ pos.top += el.y;
306
+ }
307
+ return pos;
308
+ }
309
+ /**
310
+ * 获取元素事件触发的位置
311
+ *
312
+ * @method getEventPosition
313
+ * @static
314
+ * @param {eventArg} evt 当前触发事件的参数
315
+ * @param {point} [scale] 当前画布的缩放比例
316
+ * @return {point} 事件触发的位置
317
+ */
318
+ static getEventPosition (evt, scale) {
319
+ evt = evt || event;
320
+ const isWXMiniApp = evt.isWXMiniApp;
321
+ let isTouch = false;
322
+ let touches = evt.changedTouches || evt.targetTouches || evt.touches;
323
+ let target = evt.target || evt.srcElement;
324
+ if(touches && touches.length) {
325
+ evt = touches[0];//兼容touch事件
326
+ if(!evt.target) evt.target = target;
327
+ isTouch = true;
328
+ }
329
+ let px = evt.pageX || evt.x;
330
+ if(typeof px == 'undefined') px = evt.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
331
+ let py = evt.pageY || evt.y;
332
+ if(typeof py == 'undefined') py = evt.clientY + (document.documentElement.scrollTop || document.body.scrollTop);
333
+
334
+ let ox = evt.offsetX;
335
+ let oy = evt.offsetY;
336
+ if(typeof ox === 'undefined' && typeof oy === 'undefined') {
337
+ // 小程序下取x,y就是它的相对坐标
338
+ if(isWXMiniApp) {
339
+ ox = evt.x;
340
+ oy = evt.y;
341
+ }
342
+ else {
343
+ let p = this.getElementPosition(target);
344
+ ox= px - p.left;
345
+ oy = py - p.top;
346
+ }
347
+ }
348
+ if(scale) {
349
+ if(scale.x) ox = ox / scale.x;
350
+ if(scale.y) oy = oy / scale.y;
351
+ }
352
+
353
+ return {
354
+ pageX: px,
355
+ pageY: py,
356
+ clientX: evt.clientX,
357
+ clientY: evt.clientY,
358
+ //相对于容器偏移量
359
+ offsetX: ox,
360
+ offsetY: oy,
361
+ layerX: evt.layerX,
362
+ layerY: evt.layerY,
363
+ screenX: evt.screenX,
364
+ screenY: evt.screenY,
365
+ x: ox,
366
+ y: oy,
367
+ isTouch: isTouch,
368
+ touches,
369
+ isWXMiniApp
370
+ };
371
+ }
372
+
373
+ /**
374
+ * 检 查对象是否为指定的类型,不包括继承
375
+ *
376
+ * @method isType
377
+ * @static
378
+ * @param {object} target 需要判断类型的对象
379
+ * @param {class} type 对象类型
380
+ * @return {boolean} 返回对象是否为指定类型
381
+ */
382
+ static isType(target, type) {
383
+ if(!target || typeof target !== 'object') return false;
384
+ if(target.constructor === type) return true;
385
+ /*if(target.__baseType) {
386
+ return jmUtils.isType(target.__baseType.prototype,type);
387
+ }*/
388
+
389
+ //return target instanceof type;
390
+ return false;
391
+ }
392
+ /**
393
+ * 判断点是否在多边形内
394
+ * 如果一个点在多边形内部,任意角度做射线肯定会与多边形要么有一个交点,要么有与多边形边界线重叠。
395
+ * 如果一个点在多边形外部,任意角度做射线要么与多边形有一个交点,要么有两个交点,要么没有交点,要么有与多边形边界线重叠。
396
+ * 利用上面的结论,我们只要判断这个点与多边形的交点个数,就可以判断出点与多边形的位置关系了。
397
+ *
398
+ * @method pointInPolygon
399
+ * @static
400
+ * @param {point} pt 坐标对象
401
+ * @param {array} polygon 多边型角坐标对象数组
402
+ * @param {number} offset 判断可偏移值
403
+ * @return {integer} 0= 不在图形内和线上,1=在边上,2=在图形内部
404
+ */
405
+ static pointInPolygon(pt, polygon, offset) {
406
+ offset = offset || 1;
407
+ offset = offset / 2;
408
+ const n = polygon.length;
409
+
410
+ if(!polygon || n == 0) return 0;
411
+
412
+ if(n == 1) {
413
+ return Math.abs(polygon[0].x - pt.x) <= offset && Math.abs(polygon[0].y - pt.y) <= offset ? 1 : 0;
414
+ }
415
+
416
+ if(n == 2) {
417
+ return this.pointOnLine(pt, polygon[0], polygon[1], offset);
418
+ }
419
+
420
+ for (let i = 0; i < n; i++) {
421
+ if (Math.abs(polygon[i].x - pt.x) <= offset &&
422
+ Math.abs(polygon[i].y - pt.y) <= offset) {
423
+ return 1;
424
+ }
425
+ }
426
+
427
+ return this.rayCasting(pt, polygon, offset);
428
+ }
429
+
430
+ static pointOnLine(pt, p1, p2, offset) {
431
+ const minX = Math.min(p1.x, p2.x);
432
+ const maxX = Math.max(p1.x, p2.x);
433
+ const minY = Math.min(p1.y, p2.y);
434
+ const maxY = Math.max(p1.y, p2.y);
435
+
436
+ if (minX - pt.x > offset || pt.x - maxX > offset) {
437
+ return 0;
438
+ }
439
+ if (minY - pt.y > offset || pt.y - maxY > offset) {
440
+ return 0;
441
+ }
442
+
443
+ if (p1.x == p2.x) {
444
+ return Math.abs(p1.x - pt.x) <= offset &&
445
+ (pt.y - p1.y) * (pt.y - p2.y) <= 0 ? 1 : 0;
446
+ }
447
+
448
+ if (p1.y == p2.y) {
449
+ return Math.abs(p1.y - pt.y) <= offset &&
450
+ (pt.x - p1.x) * (pt.x - p2.x) <= 0 ? 1 : 0;
451
+ }
452
+
453
+ if (Math.abs(p1.x - pt.x) < offset && Math.abs(p1.y - pt.y) < offset) {
454
+ return 1;
455
+ }
456
+ if (Math.abs(p2.x - pt.x) < offset && Math.abs(p2.y - pt.y) < offset) {
457
+ return 1;
458
+ }
459
+
460
+ if (pt.y != p1.y && pt.y != p2.y) {
461
+ const f = (p2.x - p1.x) / (p2.y - p1.y) * (pt.y - p1.y);
462
+ const ff = (pt.y - p1.y) / Math.sqrt(f * f + (pt.y - p1.y) * (pt.y - p1.y));
463
+ const l = ff * (pt.x - p1.x - f);
464
+
465
+ return Math.abs(l) <= offset ? 1 : 0;
466
+ }
467
+ return 0;
468
+ }
469
+
470
+ static rayCasting(pt, polygon, offset) {
471
+ const n = polygon.length;
472
+ let inside = false;
473
+ const testY = pt.y;
474
+ const testX = pt.x;
475
+
476
+ for (let i = 0, j = n - 1; i < n; j = i++) {
477
+ const yi = polygon[i].y;
478
+ const yj = polygon[j].y;
479
+ const xi = polygon[i].x;
480
+ const xj = polygon[j].x;
481
+
482
+ const intersect = ((yi > testY) !== (yj > testY)) &&
483
+ (testX < (xj - xi) * (testY - yi) / (yj - yi) + xi);
484
+
485
+ if (intersect) {
486
+ inside = !inside;
487
+ }
488
+ }
489
+
490
+ return inside ? 2 : 0;
491
+ }
492
+
493
+ /**
494
+ * @method judge 判断点是否在多边形中
495
+ * @param {point} dot {{x,y}} 需要判断的点
496
+ * @param {array} coordinates {{x,y}} 多边形点坐标的数组,为保证图形能够闭合,起点和终点必须相等。
497
+ * 比如三角形需要四个点表示,第一个点和最后一个点必须相同。
498
+ * @param {number} 是否为实心 1= 是
499
+ * @returns {boolean} 结果 true=在形状内
500
+ */
501
+ /*static judge(dot,coordinates,noneZeroMode) {
502
+ // 默认启动none zero mode
503
+ noneZeroMode=noneZeroMode||1;
504
+ var x = dot.x,y=dot.y;
505
+ var crossNum = 0;
506
+ // 点在线段的左侧数目
507
+ var leftCount = 0;
508
+ // 点在线段的右侧数目
509
+ var rightCount = 0;
510
+ for(var i=0;i<coordinates.length-1;i++){
511
+ var start = coordinates[i];
512
+ var end = coordinates[i+1];
513
+
514
+ // 起点、终点斜率不存在的情况
515
+ if(start.x===end.x) {
516
+ // 因为射线向右水平,此处说明不相交
517
+ if(x>start.x) continue;
518
+
519
+ // 从左侧贯穿
520
+ if((end.y>start.y&&y>=start.y && y<=end.y)){
521
+ leftCount++;
522
+ crossNum++;
523
+ }
524
+ // 从右侧贯穿
525
+ if((end.y<start.y&&y>=end.y && y<=start.y)) {
526
+ rightCount++;
527
+ crossNum++;
528
+ }
529
+ continue;
530
+ }
531
+ // 斜率存在的情况,计算斜率
532
+ var k=(end.y-start.y)/(end.x-start.x);
533
+ // 交点的x坐标
534
+ var x0 = (y-start.y)/k+start.x;
535
+ // 因为射线向右水平,此处说明不相交
536
+ if(x>x0) continue;
537
+
538
+ if((end.x>start.x&&x0>=start.x && x0<=end.x)){
539
+ crossNum++;
540
+ if(k>=0) leftCount++;
541
+ else rightCount++;
542
+ }
543
+ if((end.x<start.x&&x0>=end.x && x0<=start.x)) {
544
+ crossNum++;
545
+ if(k>=0) rightCount++;
546
+ else leftCount++;
547
+ }
548
+ }
549
+
550
+ return noneZeroMode===1?leftCount-rightCount!==0:crossNum%2===1;
551
+ }*/
552
+
553
+ /**
554
+ * 检查边界,子对象是否超出父容器边界
555
+ * 当对象偏移offset后是否出界
556
+ * 返回(left:0,right:0,top:0,bottom:0)
557
+ * 如果right>0表示右边出界right偏移量,left<0则表示左边出界left偏移量
558
+ * 如果bottom>0表示下边出界bottom偏移量,top<0则表示上边出界ltop偏移量
559
+ *
560
+ * @method checkOutSide
561
+ * @static
562
+ * @param {bound} parentBounds 父对象的边界
563
+ * @param {bound} targetBounds 对象的边界
564
+ * @param {number} offset 判断是否越界可容偏差
565
+ * @return {bound} 越界标识
566
+ */
567
+ static checkOutSide(parentBounds, targetBounds, offset) {
568
+ let result = {left:0,right:0,top:0,bottom:0};
569
+ if(offset.x < 0 ) {
570
+ result.left = targetBounds.left + offset.x - parentBounds.left;
571
+ }
572
+ else if(offset.x > 0 ) {
573
+ result.right = targetBounds.right + offset.x - parentBounds.right;
574
+ }
575
+
576
+ if(offset.y < 0 ) {
577
+ result.top = targetBounds.top + offset.y - parentBounds.top;
578
+ }
579
+ else if(offset.y > 0) {
580
+ result.bottom = targetBounds.bottom + offset.y - parentBounds.bottom;
581
+ }
582
+ return result;
583
+ }
584
+
585
+ /**
586
+ * 把一个或多个点绕某个点旋转一定角度
587
+ * 先把坐标原点移到旋转中心点,计算后移回
588
+ * @method rotatePoints
589
+ * @static
590
+ * @param {Array/object} p 一个或多个点
591
+ * @param {*} rp 旋转中心点
592
+ * @param {*} r 旋转角度
593
+ */
594
+ static rotatePoints(p, rp, r) {
595
+ if(!r || !p) return p;
596
+ let cos = Math.cos(r);
597
+ let sin = Math.sin(r);
598
+ if(Array.isArray(p)) {
599
+ for(let i=0;i<p.length;i++) {
600
+ if(!p[i]) continue;
601
+ let x1 = p[i].x - rp.x;
602
+ let y1 = p[i].y - rp.y;
603
+ p[i].x = x1 * cos - y1 * sin + rp.x;
604
+ p[i].y = x1 * sin + y1 * cos + rp.y;
605
+ }
606
+ }
607
+ else {
608
+ let x1 = p.x - rp.x;
609
+ let y1 = p.y - rp.y;
610
+ p.x = x1 * cos - y1 * sin + rp.x;
611
+ p.y = x1 * sin + y1 * cos + rp.y;
612
+ }
613
+ return p;
614
+ }
615
+
616
+ /**
617
+ * 去除字符串开始字符
618
+ *
619
+ * @method trimStart
620
+ * @static
621
+ * @param {string} source 需要处理的字符串
622
+ * @param {char} [c] 要去除字符串的前置字符
623
+ * @return {string} 去除前置字符后的字符串
624
+ */
625
+ static trimStart(source, c) {
626
+ c = c || ' ';
627
+ if(source && source.length > 0) {
628
+ let sc = source[0];
629
+ if(sc === c || c.indexOf(sc) >= 0) {
630
+ source = source.substring(1);
631
+ return this.trimStart(source,c);
632
+ }
633
+ }
634
+ return source;
635
+ }
636
+
637
+ /**
638
+ * 去除字符串结束的字符c
639
+ *
640
+ * @method trimEnd
641
+ * @static
642
+ * @param {string} source 需要处理的字符串
643
+ * @param {char} [c] 要去除字符串的后置字符
644
+ * @return {string} 去除后置字符后的字符串
645
+ */
646
+ static trimEnd(source, c) {
647
+ c = c || ' ';
648
+ if(source && source.length > 0) {
649
+ let sc = source[source.length - 1];
650
+ if(sc === c || c.indexOf(sc) >= 0) {
651
+ source = source.substring(0,source.length - 1);
652
+ return this.trimStart(source,c);
653
+ }
654
+ }
655
+ return source;
656
+ }
657
+
658
+ /**
659
+ * 去除字符串开始与结束的字符
660
+ *
661
+ * @method trim
662
+ * @static
663
+ * @param {string} source 需要处理的字符串
664
+ * @param {char} [c] 要去除字符串的字符
665
+ * @return {string} 去除字符后的字符串
666
+ */
667
+ static trim(source,c) {
668
+ return this.trimEnd(this.trimStart(source,c),c);
669
+ }
670
+
671
+ /**
672
+ * 检查是否为百分比参数
673
+ *
674
+ * @method checkPercent
675
+ * @static
676
+ * @param {string} 字符串参数
677
+ * @return {boolean} true=当前字符串为百分比参数,false=不是
678
+ */
679
+ static checkPercent(per) {
680
+ if(typeof per === 'string') {
681
+ per = this.trim(per);
682
+ if(per[per.length - 1] == '%') {
683
+ return per;
684
+ }
685
+ }
686
+ }
687
+
688
+ /**
689
+ * 转换百分数为数值类型
690
+ *
691
+ * @method percentToNumber
692
+ * @static
693
+ * @param {string} per 把百分比转为数值的参数
694
+ * @return {number} 百分比对应的数值
695
+ */
696
+ static percentToNumber(per) {
697
+ if(typeof per === 'string') {
698
+ let tmp = this.checkPercent(per);
699
+ if(tmp) {
700
+ per = this.trim(tmp,'% ');
701
+ per = per / 100;
702
+ }
703
+ }
704
+ return per;
705
+ }
706
+
707
+ /**
708
+ * 转换16进制为数值
709
+ *
710
+ * @method hexToNumber
711
+ * @static
712
+ * @param {string} h 16进制颜色表达
713
+ * @return {number} 10进制表达
714
+ */
715
+ static hexToNumber(h) {
716
+ if(typeof h !== 'string') return h;
717
+
718
+ h = h.toLowerCase();
719
+ let hex = '0123456789abcdef';
720
+ let v = 0;
721
+ let l = h.length;
722
+ for(let i=0;i<l;i++) {
723
+ let iv = hex.indexOf(h[i]);
724
+ if(iv == 0) continue;
725
+
726
+ for(let j=1;j<l - i;j++) {
727
+ iv *= 16;
728
+ }
729
+ v += iv;
730
+ }
731
+ return v;
732
+ }
733
+
734
+ /**
735
+ * 转换数值为16进制字符串表达
736
+ *
737
+ * @method hex
738
+ * @static
739
+ * @param {number} v 数值
740
+ * @return {string} 16进制表达
741
+ */
742
+ static numberToHex(v) {
743
+ let hex = '0123456789abcdef';
744
+
745
+ let h = '';
746
+ while(v > 0) {
747
+ let t = v % 16;
748
+ h = hex[t] + h;
749
+ v = Math.floor(v / 16);
750
+ }
751
+ return h;
752
+ }
753
+
754
+ /**
755
+ * 16进制颜色转为r g b a 对象 {r, g , b, a}
756
+ * @param {string}} hex 16进度的颜色
757
+ */
758
+ static hexToRGBA(hex) {
759
+ if(typeof hex === 'string') hex = this.trim(hex);
760
+ else return hex;
761
+
762
+ // 如果缓存存在,则直接返回
763
+ this.__hexToRGBA_Cache = this.__hexToRGBA_Cache || {};
764
+ if(this.__hexToRGBA_Cache[hex]) return this.__hexToRGBA_Cache[hex];
765
+
766
+ let res = hex;
767
+
768
+ // 系统颜色
769
+ if(colorKeywords[res]) res = colorKeywords[res];
770
+
771
+ //当为7位时,表示需要转为带透明度的rgba
772
+ if(res[0] == '#') {
773
+ const color = {
774
+ a: 1
775
+ };
776
+ if(res.length >= 8) {
777
+ color.a = res.substr(1,2);
778
+ color.g = res.substr(5,2);
779
+ color.b = res.substr(7,2);
780
+ color.r = res.substr(3,2);
781
+ //透明度
782
+ color.a = Number((this.hexToNumber(color.a) / 255).toFixed(4));
783
+
784
+ color.r = this.hexToNumber(color.r||0);
785
+ color.g = this.hexToNumber(color.g||0);
786
+ color.b = this.hexToNumber(color.b||0);
787
+ res = color;
788
+ }
789
+ // #cccccc || #ccc
790
+ else if(res.length === 7 || res.length === 4) {
791
+ // #ccc这种情况,把每个位复制一份
792
+ if(res.length === 4) {
793
+ color.g = res.substr(2, 1);
794
+ color.g = color.g + color.g;
795
+ color.b = res.substr(3, 1);
796
+ color.b = color.b + color.b;
797
+ color.r = res.substr(1, 1);
798
+ color.r = color.r + color.r;
799
+ }
800
+ else {
801
+ color.g = res.substr(3, 2);//除#号外的第二位
802
+ color.b = res.substr(5, 2);
803
+ color.r = res.substr(1, 2);
804
+ }
805
+
806
+ color.r = this.hexToNumber(color.r||0);
807
+ color.g = this.hexToNumber(color.g||0);
808
+ color.b = this.hexToNumber(color.b||0);
809
+
810
+ res = color;
811
+ }
812
+ //如果是5位的话,# 则第2位表示A,后面依次是r,g,b
813
+ else if(res.length === 5) {
814
+ color.a = res.substr(1,1);
815
+ color.g = res.substr(3,1);//除#号外的第二位
816
+ color.b = res.substr(4,1);
817
+ color.r = res.substr(2,1);
818
+
819
+ color.r = this.hexToNumber(color.r||0);
820
+ color.g = this.hexToNumber(color.g||0);
821
+ color.b = this.hexToNumber(color.b||0);
822
+ //透明度
823
+ color.a = Number((this.hexToNumber(color.a) / 255).toFixed(4));
824
+ res = color;
825
+ }
826
+ }
827
+ if(typeof res === 'string') {
828
+ const m = res.match(/rgb(a)?\s*\(\s*([\d\.]+)\s*,\s*([\d\.]+)\s*,\s*([\d\.]+)\s*(,\s*[\d\.]+)?\s*\)/i);
829
+ if(m && m.length === 6) {
830
+ const color = {
831
+ r: Number(m[2]),
832
+ g: Number(m[3]),
833
+ b: Number(m[4]),
834
+ a: Number(this.trimStart(m[5]||'1', ','))
835
+ };
836
+ res = color;
837
+ }
838
+ }
839
+ return this.__hexToRGBA_Cache[hex] = res;
840
+ }
841
+
842
+ /**
843
+ * 把255的rgb值转为0-1的值
844
+ * @param {rgba} color 颜色
845
+ */
846
+ static rgbToDecimal(color) {
847
+ color = this.clone(color);
848
+ color.r = this.byteToDecimal(color.r);
849
+ color.g = this.byteToDecimal(color.g);
850
+ color.b = this.byteToDecimal(color.b);
851
+ return color;
852
+ }
853
+
854
+ //255值转为0-1的小数
855
+ static byteToDecimal(b) {
856
+ return b / 255;
857
+ }
858
+
859
+ /**
860
+ * 转换颜色格式,如果输入r,g,b则转为hex格式,如果为hex则转为r,g,b格式
861
+ *
862
+ * @method toColor
863
+ * @static
864
+ * @param {string} hex 16进制颜色表达
865
+ * @return {string} 颜色字符串
866
+ */
867
+ static toColor(r, g, b, a) {
868
+ if(typeof r === 'string' && r) {
869
+ r = this.trim(r);
870
+ // 正常的颜色表达,不需要转换
871
+ if(r[0] === '#' && (r.length === 4 || r.length === 7)) return r;
872
+
873
+ const color = this.hexToRGBA(r);
874
+ if(typeof color === 'string') return color;
875
+
876
+ r = typeof color.r !== 'undefined'? color.r: r;
877
+ g = typeof color.g !== 'undefined'? color.g: g;
878
+ b = typeof color.b !== 'undefined'? color.b: b;
879
+ a = typeof color.a !== 'undefined'? color.a: a;
880
+ }
881
+ if(r && typeof r === 'object') {
882
+ g = r.g;
883
+ b = r.b;
884
+ a = r.a || 1;
885
+ r = r.r;
886
+ }
887
+ if(typeof r != 'undefined' && typeof g != 'undefined' && typeof b != 'undefined') {
888
+ if(typeof a != 'undefined') {
889
+ return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
890
+ }
891
+ else {
892
+ return 'rgb(' + r + ',' + g + ',' + b + ')';
893
+ }
894
+ }
895
+ return r;
896
+ }
897
+ // window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
898
+ static requestAnimationFrame(callback, win) {
899
+ let fun = win && win.requestAnimationFrame? win.requestAnimationFrame: (typeof window !== 'undefined' && window.requestAnimationFrame? window.requestAnimationFrame: setTimeout);
900
+ return fun(callback, 20);
901
+ }
902
+ static cancelAnimationFrame(handler, win) {
903
+ let fun = win && win.cancelAnimationFrame? win.cancelAnimationFrame: (typeof window !== 'undefined' && window.cancelAnimationFrame? window.cancelAnimationFrame: clearTimeout);
904
+ return fun(handler);
905
+ }
906
+ }
920
907
  export { jmUtils };