()
| 611 | } |
| 612 | |
| 613 | function zoomToSelection() { |
| 614 | const ids = selectedIds && selectedIds.size ? Array.from(selectedIds) : (selectedId ? [selectedId] : []); |
| 615 | if (!ids.length) return; |
| 616 | const els = ids.map((id) => elements.find((e) => e.id === id)).filter(Boolean); |
| 617 | if (!els.length) return; |
| 618 | |
| 619 | const pad = 24; |
| 620 | let minX = Math.min(...els.map((e) => e.x)) - pad; |
| 621 | let maxX = Math.max(...els.map((e) => e.x + e.w)) + pad; |
| 622 | let minY = Math.min(...els.map((e) => e.y)) - pad; |
| 623 | let maxY = Math.max(...els.map((e) => e.y + e.h)) + pad; |
| 624 | minX = clamp(minX, 0, dispWidth); |
| 625 | minY = clamp(minY, 0, dispHeight); |
| 626 | maxX = clamp(maxX, 0, dispWidth); |
| 627 | maxY = clamp(maxY, 0, dispHeight); |
| 628 | const bw = Math.max(32, maxX - minX); |
| 629 | const bh = Math.max(32, maxY - minY); |
| 630 | |
| 631 | const wrapper = document.querySelector(".preview-wrapper"); |
| 632 | if (!wrapper || !preview) return; |
| 633 | const wr = wrapper.getBoundingClientRect(); |
| 634 | const scale = parseFloat(preview.dataset.scale || "1"); |
| 635 | let targetZ = Math.min(wr.width / (bw * scale), wr.height / (bh * scale)) * 0.9; |
| 636 | targetZ = clamp(targetZ, 0.5, 3); |
| 637 | |
| 638 | viewportPanX = 0; |
| 639 | viewportPanY = 0; |
| 640 | if (driverMode === "u8g2") { |
| 641 | setZoom(targetZ); |
| 642 | updatePreviewSize(); |
| 643 | applyViewportTransform(); |
| 644 | } else { |
| 645 | setZoom(targetZ); |
| 646 | applyViewportTransform(); |
| 647 | updatePreviewSize(); |
| 648 | } |
| 649 | renderElements(); |
| 650 | renderLayers(); |
| 651 | |
| 652 | requestAnimationFrame(() => { |
| 653 | const nodes = ids |
| 654 | .map((id) => document.querySelector(`.ui-element[data-id="${id}"]`)) |
| 655 | .filter(Boolean); |
| 656 | if (!nodes.length) return; |
| 657 | let u = null; |
| 658 | nodes.forEach((n) => { |
| 659 | const r = n.getBoundingClientRect(); |
| 660 | if (!u) u = { left: r.left, top: r.top, right: r.right, bottom: r.bottom }; |
| 661 | else { |
| 662 | u.left = Math.min(u.left, r.left); |
| 663 | u.top = Math.min(u.top, r.top); |
| 664 | u.right = Math.max(u.right, r.right); |
| 665 | u.bottom = Math.max(u.bottom, r.bottom); |
| 666 | } |
| 667 | }); |
| 668 | const wr2 = wrapper.getBoundingClientRect(); |
| 669 | const mx = (u.left + u.right) / 2; |
| 670 | const my = (u.top + u.bottom) / 2; |
no test coverage detected