首页IT科技可视化对象元素包括(可视化调试某个js对象的属性UI插件 class HTUI)

可视化对象元素包括(可视化调试某个js对象的属性UI插件 class HTUI)

时间2025-08-25 21:02:57分类IT科技浏览5506
导读:依赖的类:...

依赖的类:

1 "use strict"; 2 import { 3 UTILS, 4 Box, 5 EventDispatcher, 6 Point, 7 AnimateLoop, 8 TreeStruct, 9 Timer, 10 TweenCache, 11 RGBColor, 12 Line, 13 Polygon, 14 Circle, 15 RoundedRectangle, 16 Meter, 17 SecurityDoor, 18 } from ./Utils.js; 19 20 21 /* Touch 事件 22 touchstart 23 当用户在触摸平面上放置了一个触点时触发                 。事件的目标 element 将是触点位置上的那个目标 element 24 25 touchend 26 当一个触点被用户从触摸平面上移除(即用户的一个手指或手写笔离开触摸平面)时触发                          。当触点移出触摸平面的边界时也将触发         。例如用户将手指划出屏幕边缘        。 27 事件的目标 element 与触发 touchstart 事件的目标 element 相同                 ,即使 touchend 事件触发时                          ,触点已经移出了该 element                           。 28 已经被从触摸平面上移除的触点         ,可以在 changedTouches 属性定义的 TouchList 中找到                 。 29 30 touchmove 31 当用户在触摸平面上移动触点时触发        。事件的目标 element 和触发 touchstart 事件的目标 element 相同                 ,即使当 touchmove 事件触发时                         ,触点已经移出了该 element                           。 32 当触点的半径                 、旋转角度以及压力大小发生变化时         ,也将触发此事件                 。 33 注意: 不同浏览器上 touchmove 事件的触发频率并不相同。这个触发频率还和硬件设备的性能有关                          。因此决不能让程序的运作依赖于某个特定的触发频率                          。 34 35 touchcancel 36 当触点由于某些原因被中断时触发。有几种可能的原因如下(具体的原因根据不同的设备和浏览器有所不同): 37 由于某个事件出现而取消了触摸:例如触摸过程被弹窗打断                 。 38 触点离开了文档窗口         ,而进入了浏览器的界面元素                          、插件或者其他外部内容区域                          。 39 当用户产生的触点个数超过了设备支持的个数                         ,从而导致 TouchList 中最早的 Touch 对象被取消         。 40 41 42 TouchEvent.changedTouches 43 这个 TouchList 对象列出了和这个触摸事件对应的 Touch 对象                 。 44 对于 touchstart 事件                 ,这个 TouchList 对象列出在此次事件中新增加的触点                          。 45 对于 touchmove 事件         ,列出和上一次事件相比较                          ,发生了变化的触点         。 46 对于 touchend 事件                 ,changedTouches 是已经从触摸面的离开的触点的集合(也就是说,手指已经离开了屏幕/触摸面)        。 47 48 TouchEvent.targetTouches 49 targetTouches 是一个只读的 TouchList 列表                          ,包含仍与触摸面接触的所有触摸点的 Touch 对象                          。touchstart (en-US)事件触发在哪个element内                          ,它就是当前目标元素                 。 50 51 TouchEvent.touches 52 一个 TouchList,其会列出所有当前在与触摸表面接触的 Touch 对象                 ,不管触摸点是否已经改变或其目标元素是在处于 touchstart 阶段        。 53 54 1 event.changedTouches 上一次的触点列表 55 1 event.targetTouches 某个元素的当前触点列表 56 1 event.touches 屏幕上所有的当前触点列表 57 5 touches: Array[Object{ 58 clientX, clientY 59 pageX, pageY 60 screenX, screenY 61 radiusX, radiusY 62 force 63 identifier 64 rotationAngle 65 target 66 }] 67 68 */ 69 70 71 function _roundRect(con, x, y, w, h, r){ //con: context || Path2D 72 const _x = x + r, 73 _y = y + r, 74 mx = x + w, 75 my = y + h, 76 _mx = mx - r, 77 _my = my - r; 78 79 //上 80 con.moveTo(_x, y); 81 con.lineTo(_mx, y); 82 con.arcTo(mx, y, mx, _y, r); 83 84 //右 85 con.lineTo(mx, _y); 86 con.lineTo(mx, _my); 87 con.arcTo(mx, my, _x, my, r); 88 89 //下 90 con.lineTo(_x, my); 91 con.lineTo(_mx, my); 92 con.arcTo(x, my, x, _my, r); 93 94 //左 95 con.lineTo(x, _y); 96 con.lineTo(x, _my); 97 con.arcTo(x, y, _x, y, r); 98 } 99 100 101 const PI2 = Math.PI*2; 102 103 const ElementUtils = { 104 105 getRect(elem){ 106 return elem.getBoundingClientRect(); 107 }, 108 109 downloadFile(blob, fileName){ 110 const link = document.createElement("a"); 111 link.href = URL.createObjectURL(blob); 112 link.download = fileName; 113 link.click(); 114 }, 115 116 loadFileJSON(onload){ 117 const input = document.createElement("input"); 118 input.type = "file"; 119 input.accept = ".json"; 120 121 input.onchange = a => { 122 if(a.target.files.length === 0) return; 123 const fr = new FileReader(); 124 fr.onloadend = b => onload(b.target.result); 125 fr.readAsText(a.target.files[0]); //fr.readAsDataURL(a.target.files[0]); 126 } 127 128 input.click(); 129 }, 130 131 loadFileImages(onload){ 132 const input = document.createElement("input"); 133 input.type = "file"; 134 input.multiple = "multiple"; 135 input.accept = ".png, .PNG, .jpg, .JPG, .jpeg, .JPEG, .bmp, .BMP, .gif, .GIF"; 136 137 input.onchange = e => { 138 const files = e.target.files, len = files.length; 139 if(len === 0) return; 140 141 var i = 0; 142 const fr = new FileReader(), result = []; 143 fr.onerror = () => { 144 i++; if(i === len && typeof onload === "function") onload(result); 145 } 146 fr.onloadend = ef => { 147 if(typeof ef.target.result === "string" && ef.target.result.length > 0) result.push(ef.target.result); 148 i++; 149 if(i === len && typeof onload === "function") onload(result); 150 else fr.readAsDataURL(files[i]); 151 } 152 153 fr.readAsDataURL(files[0]); 154 } 155 156 input.click(); 157 }, 158 159 createCanvas(w = 1, h = 1, className = ""){ 160 const canvas = document.createElement("canvas"); 161 canvas.width = w; 162 canvas.height = h; 163 canvas.className = className; 164 return canvas; 165 }, 166 167 createContext(w = 1, h = 1, alpha = true){ 168 const canvas = document.createElement("canvas"), 169 context = canvas.getContext("2d", {alpha: alpha}); 170 canvas.width = w; 171 canvas.height = h; 172 return context; 173 }, 174 175 //加载图片并把图片缩放至 w, h 大小(如果与w,h大小一样则不缩放直接返回image而不是canvas); 176 //urls: Array[string]; 此参数为引用(只对urls读操作) 177 //constrainScale: 在缩放图像时是否约束其比例; 默认 false 178 createCanvasFromURL(w, h, urls, constrainScale, onload, onchange){ 179 var i = 0; 180 const len = urls.length, images = [], 181 done = () => { 182 i++; if(len !== i){ 183 if(typeof onchange === "function") onchange(i, len); 184 return; 185 } 186 187 for(let k = 0; k < len; k++){ 188 const image = images[k]; 189 if(image.width !== w || image.height !== h){ 190 const context = this.createContext(w, h, true); 191 if(constrainScale === true){ 192 const scale = UTILS.getSameScale(image, {width: w, height: h}), 193 nw = scale * image.width, 194 nh = scale * image.height; 195 context.drawImage(image, (w - nw) / 2, (h - nh) / 2, nw, nh); 196 } else { 197 context.drawImage(image, 0, 0, w, h); 198 } 199 images[k] = context.canvas; 200 } 201 } 202 203 if(typeof onload === "function") onload(images); 204 } 205 206 for(let k = 0; k < len; k++){ 207 images[k] = new Image(); 208 images[k].onload = done; 209 images[k].src = urls[k]; 210 } 211 }, 212 213 //创建画布, 并且在此画布上绘制两种颜色交叉的底板色 214 createCanvasTCC(width, height, size, round = 0, c1 = "rgb(255,255,255)", c2 = "rgb(127,127,127)"){ 215 const lenX = Math.ceil(width/size), lenY = Math.ceil(height/size), 216 con = this.createContext(width, height, true), 217 l_2 = con.lineWidth / 2, p$1 = new Path2D(), p$2 = new Path2D(); 218 219 if(round < 1){ 220 con.rect(l_2, l_2, width - con.lineWidth, height - con.lineWidth); 221 } else { 222 _roundRect(con, l_2, l_2, width - con.lineWidth, height - con.lineWidth, round); 223 con.clip(); 224 } 225 226 for(let ix = 0, iy = 0; ix < lenX; ix++){ 227 228 for(iy = 0; iy < lenY; iy++){ 229 230 ((ix + iy) % 2 === 0 ? p$1 : p$2).rect(ix * size, iy * size, size, size); 231 232 } 233 234 } 235 236 con.fillStyle = c1; 237 con.fill(p$1); 238 239 con.fillStyle = c2; 240 con.fill(p$2); 241 242 return con.canvas; 243 }, 244 245 createElem(tagName, className = "", textContent = ""){ 246 const elem = document.createElement(tagName); 247 elem.className = className; 248 elem.textContent = textContent; 249 return elem; 250 }, 251 252 createInput(type, className = ""){ 253 const input = document.createElement("input"); 254 input.type = type; 255 input.className = className; 256 return input; 257 }, 258 259 appendChilds(parentElem, ...nodes){ 260 const msgContainer = document.createDocumentFragment(); 261 for(let k = 0, len = nodes.length; k < len; k++) msgContainer.appendChild(nodes[k]); 262 parentElem.appendChild(msgContainer); 263 }, 264 265 removeChild(elem){ 266 if(elem.parentElement) elem.parentElement.removeChild(elem); 267 }, 268 269 rotate(elem, a, o = "center"){ 270 elem.style.transformOrigin = o; 271 elem.style.transform = `rotate(${a}deg)`; 272 }, 273 274 bindButton(elem, callback, ondown = null){ 275 var timeout = 0; 276 277 const param = {offsetX: 0, offsetY: 0}, 278 279 onUp = event => { 280 elem.removeEventListener(pointerup, onUp); 281 if(Date.now() - timeout < 300) callback(event, param); 282 }, 283 284 onDown = event => { 285 timeout = Date.now(); 286 param.offsetX = event.offsetX; 287 param.offsetY = event.offsetY; 288 if(ondown !== null) ondown(event, param); 289 elem.removeEventListener(pointerup, onUp); 290 elem.addEventListener(pointerup, onUp); 291 } 292 293 elem.addEventListener(pointerdown, onDown); 294 295 return function (){ 296 elem.removeEventListener(pointerup, onUp); 297 elem.removeEventListener(pointerdown, onDown); 298 } 299 }, 300 301 bindMobileButton(elem, callback, ondown = null){ 302 var timeout = 0, rect; 303 304 const param = {offsetX: 0, offsetY: 0}, 305 306 onUp = event => { 307 event.preventDefault(); 308 if(Date.now() - timeout < 300) callback(event, param); 309 }, 310 311 onDown = event => { 312 event.preventDefault(); 313 timeout = Date.now(); 314 rect = elem.getBoundingClientRect(); 315 param.offsetX = event.targetTouches[0].pageX - rect.x; 316 param.offsetY = event.targetTouches[0].pageY - rect.y; 317 if(ondown !== null) ondown(event, param); 318 } 319 320 elem.addEventListener(touchend, onUp); 321 elem.addEventListener(touchstart, onDown); 322 323 return function (){ 324 elem.removeEventListener(touchend, onUp); 325 elem.removeEventListener(touchstart, onDown); 326 } 327 }, 328 329 } 330 331 332 function gradientColor(gradient, colors, close = false){ 333 if(UTILS.emptyArray(colors)) return; 334 const len = colors.length; 335 if(close === false){ 336 for(let k = 0, _len = len - 1; k < len; k++) gradient.addColorStop(k / _len, colors[k]); 337 }else{ 338 for(let k = 0; k < len; k++) gradient.addColorStop(k / len, colors[k]); 339 gradient.addColorStop(1, colors[0]); 340 } 341 return gradient; 342 } 343 344 function gradientColorSymme(gradient, colors){ 345 if(Array.isArray(colors) === true){ 346 347 const len = Math.round(colors.length/2), count = len * 2; 348 349 for(let k = 0; k < len; k++){ 350 gradient.addColorStop(k / count, colors[k]); 351 } 352 353 for(let k = len, i = len; k >= 0; k--, i++){ 354 gradient.addColorStop(i / count, colors[k]); 355 } 356 357 } 358 return gradient; 359 } 360 361 //解决像素过高导致模糊问题 362 function setCS(c, w, h){ 363 if(devicePixelRatio <= 1){ 364 c.width = Math.round(w); 365 c.height = Math.round(h); 366 } else { 367 c.style.width = w + px; 368 c.style.height = h + px; 369 c.width = Math.round(w * devicePixelRatio); 370 c.height = Math.round(h * devicePixelRatio); 371 } 372 } 373 function getCX(x){ 374 return devicePixelRatio <= 1 ? x : x * devicePixelRatio; 375 } 376 377 378 /* CanvasElementEvent domElement 绑定 移动 桌面 down, move, up 事件 (使两端的事件触发逻辑和参数保持一致) 379 parameter: null 380 attributes: null 381 method: 382 initEvent(domElement, list, box): function; 383 initEventMobile(domElement, list, box): function; 384 domElement: HTMLCanvasElement 385 list: Array[CanvasEventTarget] 386 box: Box 387 function: 删除绑定的事件 388 */ 389 class CanvasElementEvent{ 390 391 initEvent(domElement, list, box, cis = null){ 392 const onups = []; 393 394 const ondown = event => { 395 let i, ci, len = list.length; 396 for(i = 0; i < onups.length; i++) onups[i](); 397 onups.length = 0; 398 399 const sTime = Date.now(); 400 //为什么不用event.offsetX, 而是 rect, 用rect是为了鼠标即使移出了目标dom的范围其参数值也是有效的 401 const targets = [], rect = domElement.getBoundingClientRect(), 402 _offsetX = event.pageX - rect.x, 403 _offsetY = event.pageY - rect.y, 404 offsetX = _offsetX + box.x, 405 offsetY = _offsetY + box.y; 406 407 for(i = 0; i < len; i++){ 408 ci = list[i]; 409 if(ci.visible === false) continue; 410 if(ci.position === ""){ 411 if(ci.box.containsPoint(offsetX, offsetY) === false) continue; 412 } else if(ci.position === "fixed"){ 413 if(ci.box.containsPoint(_offsetX, _offsetY) === false) continue; 414 } 415 416 if(targets.length === 0) targets[0] = ci; 417 else{ 418 if(ci.index === targets[0].index) targets.push(ci); 419 else if(ci.index > targets[0].index){ 420 targets.length = 0; 421 targets[0] = ci; 422 } 423 } 424 } 425 426 len = targets.length; 427 428 if(len !== 0){ 429 if(cis !== null) cis.disable(this); 430 const info = {targets: targets, target: targets[len-1], offsetX: offsetX, offsetY: offsetY, delta: 0, moveStep: 0}, 431 432 onmove = e => { 433 info.moveStep++; 434 info.offsetX = e.pageX - rect.x + box.x, 435 info.offsetY = e.pageY - rect.y + box.y; 436 info.delta = Date.now() - sTime; 437 for(i = 0; i < len; i++){ 438 if(targets[i].hasEventListener("move") === true) targets[i].trigger("move", info, e); 439 } 440 }, 441 442 onup = e => { 443 domElement.releasePointerCapture(e.pointerId); 444 domElement.removeEventListener("pointerup", onup); 445 domElement.removeEventListener("pointermove", onmove); 446 info.delta = Date.now() - sTime; 447 for(i = 0; i < len; i++){ 448 if(targets[i].hasEventListener("up") === true) targets[i].trigger("up", info, e); 449 } 450 451 //click 452 if(info.delta < 300 && info.moveStep === 0){ 453 for(i = 0; i < len; i++){ 454 if(targets[i].hasEventListener("click") === true) targets[i].trigger("click", info, e); 455 } 456 } 457 458 if(cis !== null) cis.enable(this); 459 } 460 461 onups.push(() => { 462 domElement.removeEventListener("pointerup", onup); 463 domElement.removeEventListener("pointermove", onmove); 464 }); 465 466 domElement.setPointerCapture(event.pointerId); 467 domElement.addEventListener("pointerup", onup); 468 domElement.addEventListener("pointermove", onmove); 469 for(i = 0; i < len; i++){ 470 if(targets[i].hasEventListener("down") === true) targets[i].trigger("down", info, event); 471 } 472 473 } 474 475 } 476 477 domElement.addEventListener("pointerdown", ondown); 478 return function (){ 479 for(let i = 0; i < onups.length; i++) onups[i](); 480 onups.length = 0; 481 domElement.removeEventListener("pointerdown", ondown); 482 if(cis !== null) cis.enable(this); 483 } 484 } 485 486 initEventMobile(domElement, list, box, cis = null){ 487 488 const ondown = event => { 489 const sTime = Date.now(); 490 event.preventDefault(); 491 let i, ci, len = list.length; 492 493 const targets = [], rect = domElement.getBoundingClientRect(), 494 _offsetX = event.targetTouches[0].pageX - rect.x, 495 _offsetY = event.targetTouches[0].pageY - rect.y, 496 offsetX = _offsetX + box.x, 497 offsetY = _offsetY + box.y; 498 499 for(i = 0; i < len; i++){ 500 ci = list[i]; 501 if(ci.visible === false) continue; 502 if(ci.position === ""){ 503 if(ci.box.containsPoint(offsetX, offsetY) === false) continue; 504 } else if(ci.position === "fixed"){ 505 if(ci.box.containsPoint(_offsetX, _offsetY) === false) continue; 506 } 507 if(targets.length === 0) targets[0] = ci; 508 else{ 509 if(ci.index === targets[0].index) targets.push(ci); 510 else if(ci.index > targets[0].index){ 511 targets.length = 0; 512 targets[0] = ci; 513 } 514 } 515 } 516 517 len = targets.length; 518 519 if(len !== 0){ 520 if(cis !== null) cis.disable(this); 521 const info = {targets: targets, target: targets[len-1], offsetX: offsetX, offsetY: offsetY, delta: 0, moveStep: 0}, 522 523 onmove = e => { 524 info.moveStep++; 525 info.offsetX = e.targetTouches[0].pageX - rect.x + box.x; 526 info.offsetY = e.targetTouches[0].pageY - rect.y + box.y; 527 info.delta = Date.now() - sTime; 528 for(i = 0; i < len; i++){ 529 if(targets[i].hasEventListener("move") === true) targets[i].trigger("move", info, e); 530 } 531 }, 532 533 onup = e => { 534 domElement.removeEventListener("touchmove", onmove); 535 domElement.removeEventListener("touchend", onup); 536 domElement.removeEventListener("touchcancel", onup); 537 info.delta = Date.now() - sTime; 538 for(i = 0; i < len; i++){ 539 if(targets[i].hasEventListener("up") === true) targets[i].trigger("up", info, e); 540 } 541 542 //click 543 if(info.delta < 300 && info.moveStep === 0){ 544 for(i = 0; i < len; i++){ 545 if(targets[i].hasEventListener("click") === true) targets[i].trigger("click", info, e); 546 } 547 } 548 549 if(cis !== null) cis.enable(this); 550 } 551 552 domElement.addEventListener("touchcancel", onup); 553 domElement.addEventListener("touchend", onup); 554 domElement.addEventListener("touchmove", onmove); 555 for(i = 0; i < len; i++){ 556 if(targets[i].hasEventListener("down") === true) targets[i].trigger("down", info, event); 557 } 558 } 559 560 } 561 562 domElement.addEventListener("touchstart", ondown); 563 return function (){ 564 domElement.removeEventListener("touchstart", ondown); 565 if(cis !== null) cis.enable(this); 566 } 567 568 } 569 570 } 571 572 573 /* CanvasPath2D CanvasImage.path2D 574 注意: 线模糊问题任然存在(只有.rect().progress()做了模糊优化) 575 parameter: 576 drawType = "stroke", drawStyle = null, order = "after" 577 578 attributes: 579 drawType: String; //填充路径或描绘路径 可能值: 默认 stroke | fill 580 drawStyle: Object; //canvas.context的属性 581 order: Bool; //是否在 CanvasImage 之前绘制 "before"||"after"默认 582 value: any; 583 584 method: 585 reset(): this; //设为零值(清空不在绘制) 586 line(line: Line): this; //线段 587 rect(rect: Box||RoundedRectangle): this; //矩形 588 circle(circle: Circle): this; //圆 589 path(polygon: Polygon): this; //线 590 progress(meter: Meter): this; //进度条(为 CanvasImage 创建默认的进度条, 修改 meter.value 更新进度条视图) 591 592 demo: 593 const test = new CanvasImageCustom().size(100, 100).pos(100, 100).rect().fill("#664466"); 594 test.path2D = new CanvasPath2D("stroke", {strokeStyle: "blue", lineWidth: 4}); 595 596 const path2D = new Path2D(); 597 path2D.roundRect(12, 12, 40, 40, 10); //圆角矩形 598 test.path2D.path(path2D); 599 600 //test.path2D.line(new Line(4, 4, 4, 150000)); 601 602 */ 603 class CanvasPath2D{ 604 605 #pathType = ""; 606 get isDraw(){ 607 return this.value && this.#pathType !== ""; 608 } 609 610 constructor(drawType = "stroke", drawStyle = null, order = "after"){ 611 this.order = order; 612 this.drawType = drawType; 613 this.drawStyle = drawStyle; 614 this.value = undefined; 615 } 616 617 reset(){ 618 this.#pathType = ""; 619 this.value = undefined; 620 return this; 621 } 622 623 line(line = new Line()){ 624 this.#pathType = "line"; 625 this.value = line; 626 return this; 627 } 628 629 rect(rect = new RoundedRectangle()){ 630 this.#pathType = "rect"; 631 this.value = rect; 632 return this; 633 } 634 635 circle(circle = new Circle()){ 636 this.#pathType = "circle"; 637 this.value = circle; 638 return this; 639 } 640 641 path(polygon = new Polygon()){ 642 this.#pathType = "path"; 643 this.value = polygon; 644 return this; 645 } 646 647 progress(meter = new Meter()){ 648 this.#pathType = "progress"; 649 this.value = meter; 650 return this; 651 } 652 653 _drawPath(con){ 654 if(this.drawStyle === null) con[this.drawType](); 655 else{ 656 con.save(); 657 for(let n in this.drawStyle){ 658 if(this.drawStyle[n] !== con[n]) con[n] = this.drawStyle[n]; 659 } 660 con[this.drawType](); 661 con.restore(); 662 } 663 } 664 665 _draw(con, x, y, w, h){ 666 var lw; 667 con.save(); 668 con.beginPath(); 669 con.rect(x, y, w, h); 670 con.clip(); 671 con.translate(x, y); 672 const val = this.value; 673 switch(this.#pathType){ 674 case "line": 675 con.beginPath(); 676 con.moveTo(val.x, val.y); 677 con.lineTo(val.x1, val.y1); 678 this._drawPath(con); 679 break; 680 681 case "rect": 682 con.beginPath(); 683 lw = this.drawStyle.lineWidth || con.lineWidth; 684 if(lw % 2 === 0){ 685 const lw_2 = lw / 2; 686 x = Math.floor(val.x+lw_2); 687 y<%2

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
电商网站产品页面设计指南(如何打造一个吸引人的产品页面) 随机森林因子权重(基于MATLAB的随机森林分类)