@framv/canvas 0.1.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/dist/bundle.esm.js +160 -0
- package/dist/bundle.iife.js +185 -0
- package/dist/cdn.d.ts +3 -0
- package/dist/cdn.d.ts.map +1 -0
- package/dist/cdn.js +3 -0
- package/dist/cdn.js.map +1 -0
- package/dist/element.d.ts +54 -0
- package/dist/element.d.ts.map +1 -0
- package/dist/element.js +188 -0
- package/dist/element.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// src/element.ts
|
|
2
|
+
var STYLES = `
|
|
3
|
+
:host {
|
|
4
|
+
display: block;
|
|
5
|
+
position: relative;
|
|
6
|
+
overflow: hidden;
|
|
7
|
+
background: #1a1a2e;
|
|
8
|
+
cursor: grab;
|
|
9
|
+
user-select: none;
|
|
10
|
+
font-family: system-ui, sans-serif;
|
|
11
|
+
}
|
|
12
|
+
:host(.framv-grabbing) { cursor: grabbing; }
|
|
13
|
+
.framv-canvas-stage {
|
|
14
|
+
position: absolute;
|
|
15
|
+
top: 0; left: 0;
|
|
16
|
+
transform-origin: 0 0;
|
|
17
|
+
will-change: transform;
|
|
18
|
+
}
|
|
19
|
+
.framv-canvas-stage > * {
|
|
20
|
+
position: absolute;
|
|
21
|
+
}
|
|
22
|
+
.framv-canvas-badge {
|
|
23
|
+
position: absolute; top: 8px; left: 8px;
|
|
24
|
+
background: rgba(0,0,0,0.5); color: rgba(255,255,255,0.7);
|
|
25
|
+
padding: 3px 8px; border-radius: 4px;
|
|
26
|
+
font: 10px system-ui; z-index: 10;
|
|
27
|
+
pointer-events: none;
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
var FramvCanvasElement = class extends HTMLElement {
|
|
31
|
+
static observedAttributes = ["scale"];
|
|
32
|
+
_stage;
|
|
33
|
+
_shadow;
|
|
34
|
+
_scale = 1;
|
|
35
|
+
_tx = 0;
|
|
36
|
+
_ty = 0;
|
|
37
|
+
_panning = false;
|
|
38
|
+
_lastX = 0;
|
|
39
|
+
_lastY = 0;
|
|
40
|
+
_minScale = 0.1;
|
|
41
|
+
_maxScale = 5;
|
|
42
|
+
constructor() {
|
|
43
|
+
super();
|
|
44
|
+
this._shadow = this.attachShadow({ mode: "open" });
|
|
45
|
+
}
|
|
46
|
+
get width() {
|
|
47
|
+
return parseInt(this.getAttribute("width") ?? "3000");
|
|
48
|
+
}
|
|
49
|
+
get height() {
|
|
50
|
+
return parseInt(this.getAttribute("height") ?? "2000");
|
|
51
|
+
}
|
|
52
|
+
connectedCallback() {
|
|
53
|
+
const s = parseFloat(this.getAttribute("scale") ?? "1");
|
|
54
|
+
this._scale = Math.min(Math.max(s, this._minScale), this._maxScale);
|
|
55
|
+
const containerW = this.clientWidth || 800;
|
|
56
|
+
const containerH = this.clientHeight || 600;
|
|
57
|
+
this._tx = (containerW - this.width * this._scale) / 2;
|
|
58
|
+
this._ty = (containerH - this.height * this._scale) / 2;
|
|
59
|
+
this._shadow.innerHTML = `
|
|
60
|
+
<style>${STYLES}</style>
|
|
61
|
+
<div class="framv-canvas-badge">${Math.round(this._scale * 100)}%</div>
|
|
62
|
+
<div class="framv-canvas-stage" style="width:${this.width}px;height:${this.height}px">
|
|
63
|
+
<slot></slot>
|
|
64
|
+
</div>
|
|
65
|
+
`;
|
|
66
|
+
this._stage = this._shadow.querySelector(".framv-canvas-stage");
|
|
67
|
+
this._updateTransform();
|
|
68
|
+
this.addEventListener(
|
|
69
|
+
"wheel",
|
|
70
|
+
(e) => {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
const rect = this.getBoundingClientRect();
|
|
73
|
+
const px = e.clientX - rect.left;
|
|
74
|
+
const py = e.clientY - rect.top;
|
|
75
|
+
const delta = -e.deltaY * 1e-3;
|
|
76
|
+
const newScale = Math.min(Math.max(this._scale * (1 + delta), this._minScale), this._maxScale);
|
|
77
|
+
const worldX = (px - this._tx) / this._scale;
|
|
78
|
+
const worldY = (py - this._ty) / this._scale;
|
|
79
|
+
this._tx = px - worldX * newScale;
|
|
80
|
+
this._ty = py - worldY * newScale;
|
|
81
|
+
this._scale = newScale;
|
|
82
|
+
this._updateTransform();
|
|
83
|
+
this._updateBadge();
|
|
84
|
+
},
|
|
85
|
+
{ passive: false }
|
|
86
|
+
);
|
|
87
|
+
this.addEventListener("pointerdown", (e) => {
|
|
88
|
+
if (e.target instanceof HTMLElement && e.target.closest("button, a, input, select, textarea, [contenteditable]")) return;
|
|
89
|
+
this._panning = true;
|
|
90
|
+
this._lastX = e.clientX;
|
|
91
|
+
this._lastY = e.clientY;
|
|
92
|
+
this.classList.add("framv-grabbing");
|
|
93
|
+
this.setPointerCapture(e.pointerId);
|
|
94
|
+
});
|
|
95
|
+
this.addEventListener("pointermove", (e) => {
|
|
96
|
+
if (!this._panning) return;
|
|
97
|
+
const dx = e.clientX - this._lastX;
|
|
98
|
+
const dy = e.clientY - this._lastY;
|
|
99
|
+
this._tx += dx;
|
|
100
|
+
this._ty += dy;
|
|
101
|
+
this._lastX = e.clientX;
|
|
102
|
+
this._lastY = e.clientY;
|
|
103
|
+
this._updateTransform();
|
|
104
|
+
});
|
|
105
|
+
this.addEventListener("pointerup", () => {
|
|
106
|
+
this._panning = false;
|
|
107
|
+
this.classList.remove("framv-grabbing");
|
|
108
|
+
});
|
|
109
|
+
this.addEventListener("pointerleave", () => {
|
|
110
|
+
if (this._panning) {
|
|
111
|
+
this._panning = false;
|
|
112
|
+
this.classList.remove("framv-grabbing");
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
attributeChangedCallback(name, _old, value) {
|
|
117
|
+
if (name === "scale" && this._stage) {
|
|
118
|
+
const s = parseFloat(value);
|
|
119
|
+
if (!isNaN(s)) {
|
|
120
|
+
this._scale = Math.min(Math.max(s, this._minScale), this._maxScale);
|
|
121
|
+
this._updateTransform();
|
|
122
|
+
this._updateBadge();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Pan to center a specific position. */
|
|
127
|
+
centerAt(x, y) {
|
|
128
|
+
const containerW = this.clientWidth || 800;
|
|
129
|
+
const containerH = this.clientHeight || 600;
|
|
130
|
+
this._tx = containerW / 2 - x * this._scale;
|
|
131
|
+
this._ty = containerH / 2 - y * this._scale;
|
|
132
|
+
this._updateTransform();
|
|
133
|
+
}
|
|
134
|
+
/** Reset to initial centered view. */
|
|
135
|
+
reset() {
|
|
136
|
+
this._scale = 1;
|
|
137
|
+
const containerW = this.clientWidth || 800;
|
|
138
|
+
const containerH = this.clientHeight || 600;
|
|
139
|
+
this._tx = (containerW - this.width) / 2;
|
|
140
|
+
this._ty = (containerH - this.height) / 2;
|
|
141
|
+
this._updateTransform();
|
|
142
|
+
this._updateBadge();
|
|
143
|
+
}
|
|
144
|
+
get scale() {
|
|
145
|
+
return this._scale;
|
|
146
|
+
}
|
|
147
|
+
_updateTransform() {
|
|
148
|
+
this._stage.style.transform = `translate(${this._tx}px, ${this._ty}px) scale(${this._scale})`;
|
|
149
|
+
}
|
|
150
|
+
_updateBadge() {
|
|
151
|
+
const badge = this._shadow.querySelector(".framv-canvas-badge");
|
|
152
|
+
if (badge) badge.textContent = `${Math.round(this._scale * 100)}%`;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
if (!customElements.get("framv-canvas")) {
|
|
156
|
+
customElements.define("framv-canvas", FramvCanvasElement);
|
|
157
|
+
}
|
|
158
|
+
export {
|
|
159
|
+
FramvCanvasElement
|
|
160
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var FramvCanvas = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/cdn.ts
|
|
22
|
+
var cdn_exports = {};
|
|
23
|
+
__export(cdn_exports, {
|
|
24
|
+
FramvCanvasElement: () => FramvCanvasElement
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// src/element.ts
|
|
28
|
+
var STYLES = `
|
|
29
|
+
:host {
|
|
30
|
+
display: block;
|
|
31
|
+
position: relative;
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
background: #1a1a2e;
|
|
34
|
+
cursor: grab;
|
|
35
|
+
user-select: none;
|
|
36
|
+
font-family: system-ui, sans-serif;
|
|
37
|
+
}
|
|
38
|
+
:host(.framv-grabbing) { cursor: grabbing; }
|
|
39
|
+
.framv-canvas-stage {
|
|
40
|
+
position: absolute;
|
|
41
|
+
top: 0; left: 0;
|
|
42
|
+
transform-origin: 0 0;
|
|
43
|
+
will-change: transform;
|
|
44
|
+
}
|
|
45
|
+
.framv-canvas-stage > * {
|
|
46
|
+
position: absolute;
|
|
47
|
+
}
|
|
48
|
+
.framv-canvas-badge {
|
|
49
|
+
position: absolute; top: 8px; left: 8px;
|
|
50
|
+
background: rgba(0,0,0,0.5); color: rgba(255,255,255,0.7);
|
|
51
|
+
padding: 3px 8px; border-radius: 4px;
|
|
52
|
+
font: 10px system-ui; z-index: 10;
|
|
53
|
+
pointer-events: none;
|
|
54
|
+
}
|
|
55
|
+
`;
|
|
56
|
+
var FramvCanvasElement = class extends HTMLElement {
|
|
57
|
+
static observedAttributes = ["scale"];
|
|
58
|
+
_stage;
|
|
59
|
+
_shadow;
|
|
60
|
+
_scale = 1;
|
|
61
|
+
_tx = 0;
|
|
62
|
+
_ty = 0;
|
|
63
|
+
_panning = false;
|
|
64
|
+
_lastX = 0;
|
|
65
|
+
_lastY = 0;
|
|
66
|
+
_minScale = 0.1;
|
|
67
|
+
_maxScale = 5;
|
|
68
|
+
constructor() {
|
|
69
|
+
super();
|
|
70
|
+
this._shadow = this.attachShadow({ mode: "open" });
|
|
71
|
+
}
|
|
72
|
+
get width() {
|
|
73
|
+
return parseInt(this.getAttribute("width") ?? "3000");
|
|
74
|
+
}
|
|
75
|
+
get height() {
|
|
76
|
+
return parseInt(this.getAttribute("height") ?? "2000");
|
|
77
|
+
}
|
|
78
|
+
connectedCallback() {
|
|
79
|
+
const s = parseFloat(this.getAttribute("scale") ?? "1");
|
|
80
|
+
this._scale = Math.min(Math.max(s, this._minScale), this._maxScale);
|
|
81
|
+
const containerW = this.clientWidth || 800;
|
|
82
|
+
const containerH = this.clientHeight || 600;
|
|
83
|
+
this._tx = (containerW - this.width * this._scale) / 2;
|
|
84
|
+
this._ty = (containerH - this.height * this._scale) / 2;
|
|
85
|
+
this._shadow.innerHTML = `
|
|
86
|
+
<style>${STYLES}</style>
|
|
87
|
+
<div class="framv-canvas-badge">${Math.round(this._scale * 100)}%</div>
|
|
88
|
+
<div class="framv-canvas-stage" style="width:${this.width}px;height:${this.height}px">
|
|
89
|
+
<slot></slot>
|
|
90
|
+
</div>
|
|
91
|
+
`;
|
|
92
|
+
this._stage = this._shadow.querySelector(".framv-canvas-stage");
|
|
93
|
+
this._updateTransform();
|
|
94
|
+
this.addEventListener(
|
|
95
|
+
"wheel",
|
|
96
|
+
(e) => {
|
|
97
|
+
e.preventDefault();
|
|
98
|
+
const rect = this.getBoundingClientRect();
|
|
99
|
+
const px = e.clientX - rect.left;
|
|
100
|
+
const py = e.clientY - rect.top;
|
|
101
|
+
const delta = -e.deltaY * 1e-3;
|
|
102
|
+
const newScale = Math.min(Math.max(this._scale * (1 + delta), this._minScale), this._maxScale);
|
|
103
|
+
const worldX = (px - this._tx) / this._scale;
|
|
104
|
+
const worldY = (py - this._ty) / this._scale;
|
|
105
|
+
this._tx = px - worldX * newScale;
|
|
106
|
+
this._ty = py - worldY * newScale;
|
|
107
|
+
this._scale = newScale;
|
|
108
|
+
this._updateTransform();
|
|
109
|
+
this._updateBadge();
|
|
110
|
+
},
|
|
111
|
+
{ passive: false }
|
|
112
|
+
);
|
|
113
|
+
this.addEventListener("pointerdown", (e) => {
|
|
114
|
+
if (e.target instanceof HTMLElement && e.target.closest("button, a, input, select, textarea, [contenteditable]")) return;
|
|
115
|
+
this._panning = true;
|
|
116
|
+
this._lastX = e.clientX;
|
|
117
|
+
this._lastY = e.clientY;
|
|
118
|
+
this.classList.add("framv-grabbing");
|
|
119
|
+
this.setPointerCapture(e.pointerId);
|
|
120
|
+
});
|
|
121
|
+
this.addEventListener("pointermove", (e) => {
|
|
122
|
+
if (!this._panning) return;
|
|
123
|
+
const dx = e.clientX - this._lastX;
|
|
124
|
+
const dy = e.clientY - this._lastY;
|
|
125
|
+
this._tx += dx;
|
|
126
|
+
this._ty += dy;
|
|
127
|
+
this._lastX = e.clientX;
|
|
128
|
+
this._lastY = e.clientY;
|
|
129
|
+
this._updateTransform();
|
|
130
|
+
});
|
|
131
|
+
this.addEventListener("pointerup", () => {
|
|
132
|
+
this._panning = false;
|
|
133
|
+
this.classList.remove("framv-grabbing");
|
|
134
|
+
});
|
|
135
|
+
this.addEventListener("pointerleave", () => {
|
|
136
|
+
if (this._panning) {
|
|
137
|
+
this._panning = false;
|
|
138
|
+
this.classList.remove("framv-grabbing");
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
attributeChangedCallback(name, _old, value) {
|
|
143
|
+
if (name === "scale" && this._stage) {
|
|
144
|
+
const s = parseFloat(value);
|
|
145
|
+
if (!isNaN(s)) {
|
|
146
|
+
this._scale = Math.min(Math.max(s, this._minScale), this._maxScale);
|
|
147
|
+
this._updateTransform();
|
|
148
|
+
this._updateBadge();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** Pan to center a specific position. */
|
|
153
|
+
centerAt(x, y) {
|
|
154
|
+
const containerW = this.clientWidth || 800;
|
|
155
|
+
const containerH = this.clientHeight || 600;
|
|
156
|
+
this._tx = containerW / 2 - x * this._scale;
|
|
157
|
+
this._ty = containerH / 2 - y * this._scale;
|
|
158
|
+
this._updateTransform();
|
|
159
|
+
}
|
|
160
|
+
/** Reset to initial centered view. */
|
|
161
|
+
reset() {
|
|
162
|
+
this._scale = 1;
|
|
163
|
+
const containerW = this.clientWidth || 800;
|
|
164
|
+
const containerH = this.clientHeight || 600;
|
|
165
|
+
this._tx = (containerW - this.width) / 2;
|
|
166
|
+
this._ty = (containerH - this.height) / 2;
|
|
167
|
+
this._updateTransform();
|
|
168
|
+
this._updateBadge();
|
|
169
|
+
}
|
|
170
|
+
get scale() {
|
|
171
|
+
return this._scale;
|
|
172
|
+
}
|
|
173
|
+
_updateTransform() {
|
|
174
|
+
this._stage.style.transform = `translate(${this._tx}px, ${this._ty}px) scale(${this._scale})`;
|
|
175
|
+
}
|
|
176
|
+
_updateBadge() {
|
|
177
|
+
const badge = this._shadow.querySelector(".framv-canvas-badge");
|
|
178
|
+
if (badge) badge.textContent = `${Math.round(this._scale * 100)}%`;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
if (!customElements.get("framv-canvas")) {
|
|
182
|
+
customElements.define("framv-canvas", FramvCanvasElement);
|
|
183
|
+
}
|
|
184
|
+
return __toCommonJS(cdn_exports);
|
|
185
|
+
})();
|
package/dist/cdn.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn.d.ts","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/cdn.js
ADDED
package/dist/cdn.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn.js","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<framv-canvas>` — infinite canvas for positioning elements.
|
|
3
|
+
*
|
|
4
|
+
* Children are absolutely positioned via `left`, `top` CSS properties.
|
|
5
|
+
* Use `data-x` and `data-y` attributes to set position.
|
|
6
|
+
*
|
|
7
|
+
* Interactions:
|
|
8
|
+
* - Drag empty space to pan
|
|
9
|
+
* - Ctrl+wheel or pinch to zoom
|
|
10
|
+
* - Click children normally (events pass through)
|
|
11
|
+
*
|
|
12
|
+
* Attributes:
|
|
13
|
+
* width — canvas logical width (default: 3000)
|
|
14
|
+
* height — canvas logical height (default: 2000)
|
|
15
|
+
* scale — initial zoom level (default: 1)
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```html
|
|
19
|
+
* <framv-canvas style="width:100%;height:500px">
|
|
20
|
+
* <div style="left:100px;top:80px;width:200px;background:#ff79c6;padding:16px;border-radius:8px;color:white">
|
|
21
|
+
* Box at (100, 80)
|
|
22
|
+
* </div>
|
|
23
|
+
* <div style="left:500px;top:200px;background:#50fa7b;padding:12px;border-radius:4px">
|
|
24
|
+
* Another box
|
|
25
|
+
* </div>
|
|
26
|
+
* </framv-canvas>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class FramvCanvasElement extends HTMLElement {
|
|
30
|
+
static observedAttributes: string[];
|
|
31
|
+
private _stage;
|
|
32
|
+
private _shadow;
|
|
33
|
+
private _scale;
|
|
34
|
+
private _tx;
|
|
35
|
+
private _ty;
|
|
36
|
+
private _panning;
|
|
37
|
+
private _lastX;
|
|
38
|
+
private _lastY;
|
|
39
|
+
private _minScale;
|
|
40
|
+
private _maxScale;
|
|
41
|
+
constructor();
|
|
42
|
+
get width(): number;
|
|
43
|
+
get height(): number;
|
|
44
|
+
connectedCallback(): void;
|
|
45
|
+
attributeChangedCallback(name: string, _old: string, value: string): void;
|
|
46
|
+
/** Pan to center a specific position. */
|
|
47
|
+
centerAt(x: number, y: number): void;
|
|
48
|
+
/** Reset to initial centered view. */
|
|
49
|
+
reset(): void;
|
|
50
|
+
get scale(): number;
|
|
51
|
+
private _updateTransform;
|
|
52
|
+
private _updateBadge;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=element.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"AA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,kBAAmB,SAAQ,WAAW;IACjD,MAAM,CAAC,kBAAkB,WAAa;IAEtC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,SAAS,CAAK;;IAOtB,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,iBAAiB,IAAI,IAAI;IAgFzB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAWzE,yCAAyC;IACzC,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAQpC,sCAAsC;IACtC,KAAK,IAAI,IAAI;IAUb,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,YAAY;CAIrB"}
|
package/dist/element.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
const STYLES = `
|
|
2
|
+
:host {
|
|
3
|
+
display: block;
|
|
4
|
+
position: relative;
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
background: #1a1a2e;
|
|
7
|
+
cursor: grab;
|
|
8
|
+
user-select: none;
|
|
9
|
+
font-family: system-ui, sans-serif;
|
|
10
|
+
}
|
|
11
|
+
:host(.framv-grabbing) { cursor: grabbing; }
|
|
12
|
+
.framv-canvas-stage {
|
|
13
|
+
position: absolute;
|
|
14
|
+
top: 0; left: 0;
|
|
15
|
+
transform-origin: 0 0;
|
|
16
|
+
will-change: transform;
|
|
17
|
+
}
|
|
18
|
+
.framv-canvas-stage > * {
|
|
19
|
+
position: absolute;
|
|
20
|
+
}
|
|
21
|
+
.framv-canvas-badge {
|
|
22
|
+
position: absolute; top: 8px; left: 8px;
|
|
23
|
+
background: rgba(0,0,0,0.5); color: rgba(255,255,255,0.7);
|
|
24
|
+
padding: 3px 8px; border-radius: 4px;
|
|
25
|
+
font: 10px system-ui; z-index: 10;
|
|
26
|
+
pointer-events: none;
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
/**
|
|
30
|
+
* `<framv-canvas>` — infinite canvas for positioning elements.
|
|
31
|
+
*
|
|
32
|
+
* Children are absolutely positioned via `left`, `top` CSS properties.
|
|
33
|
+
* Use `data-x` and `data-y` attributes to set position.
|
|
34
|
+
*
|
|
35
|
+
* Interactions:
|
|
36
|
+
* - Drag empty space to pan
|
|
37
|
+
* - Ctrl+wheel or pinch to zoom
|
|
38
|
+
* - Click children normally (events pass through)
|
|
39
|
+
*
|
|
40
|
+
* Attributes:
|
|
41
|
+
* width — canvas logical width (default: 3000)
|
|
42
|
+
* height — canvas logical height (default: 2000)
|
|
43
|
+
* scale — initial zoom level (default: 1)
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```html
|
|
47
|
+
* <framv-canvas style="width:100%;height:500px">
|
|
48
|
+
* <div style="left:100px;top:80px;width:200px;background:#ff79c6;padding:16px;border-radius:8px;color:white">
|
|
49
|
+
* Box at (100, 80)
|
|
50
|
+
* </div>
|
|
51
|
+
* <div style="left:500px;top:200px;background:#50fa7b;padding:12px;border-radius:4px">
|
|
52
|
+
* Another box
|
|
53
|
+
* </div>
|
|
54
|
+
* </framv-canvas>
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export class FramvCanvasElement extends HTMLElement {
|
|
58
|
+
static observedAttributes = ["scale"];
|
|
59
|
+
_stage;
|
|
60
|
+
_shadow;
|
|
61
|
+
_scale = 1;
|
|
62
|
+
_tx = 0;
|
|
63
|
+
_ty = 0;
|
|
64
|
+
_panning = false;
|
|
65
|
+
_lastX = 0;
|
|
66
|
+
_lastY = 0;
|
|
67
|
+
_minScale = 0.1;
|
|
68
|
+
_maxScale = 5;
|
|
69
|
+
constructor() {
|
|
70
|
+
super();
|
|
71
|
+
this._shadow = this.attachShadow({ mode: "open" });
|
|
72
|
+
}
|
|
73
|
+
get width() {
|
|
74
|
+
return parseInt(this.getAttribute("width") ?? "3000");
|
|
75
|
+
}
|
|
76
|
+
get height() {
|
|
77
|
+
return parseInt(this.getAttribute("height") ?? "2000");
|
|
78
|
+
}
|
|
79
|
+
connectedCallback() {
|
|
80
|
+
const s = parseFloat(this.getAttribute("scale") ?? "1");
|
|
81
|
+
this._scale = Math.min(Math.max(s, this._minScale), this._maxScale);
|
|
82
|
+
// Center the view initially
|
|
83
|
+
const containerW = this.clientWidth || 800;
|
|
84
|
+
const containerH = this.clientHeight || 600;
|
|
85
|
+
this._tx = (containerW - this.width * this._scale) / 2;
|
|
86
|
+
this._ty = (containerH - this.height * this._scale) / 2;
|
|
87
|
+
this._shadow.innerHTML = `
|
|
88
|
+
<style>${STYLES}</style>
|
|
89
|
+
<div class="framv-canvas-badge">${Math.round(this._scale * 100)}%</div>
|
|
90
|
+
<div class="framv-canvas-stage" style="width:${this.width}px;height:${this.height}px">
|
|
91
|
+
<slot></slot>
|
|
92
|
+
</div>
|
|
93
|
+
`;
|
|
94
|
+
this._stage = this._shadow.querySelector(".framv-canvas-stage");
|
|
95
|
+
this._updateTransform();
|
|
96
|
+
// Mouse wheel zoom (Ctrl + wheel or just wheel)
|
|
97
|
+
this.addEventListener("wheel", (e) => {
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
const rect = this.getBoundingClientRect();
|
|
100
|
+
const px = e.clientX - rect.left;
|
|
101
|
+
const py = e.clientY - rect.top;
|
|
102
|
+
const delta = -e.deltaY * 0.001;
|
|
103
|
+
const newScale = Math.min(Math.max(this._scale * (1 + delta), this._minScale), this._maxScale);
|
|
104
|
+
// Pointer-aware zoom
|
|
105
|
+
const worldX = (px - this._tx) / this._scale;
|
|
106
|
+
const worldY = (py - this._ty) / this._scale;
|
|
107
|
+
this._tx = px - worldX * newScale;
|
|
108
|
+
this._ty = py - worldY * newScale;
|
|
109
|
+
this._scale = newScale;
|
|
110
|
+
this._updateTransform();
|
|
111
|
+
this._updateBadge();
|
|
112
|
+
}, { passive: false });
|
|
113
|
+
// Pointer drag to pan
|
|
114
|
+
this.addEventListener("pointerdown", (e) => {
|
|
115
|
+
if (e.target instanceof HTMLElement && e.target.closest("button, a, input, select, textarea, [contenteditable]"))
|
|
116
|
+
return;
|
|
117
|
+
this._panning = true;
|
|
118
|
+
this._lastX = e.clientX;
|
|
119
|
+
this._lastY = e.clientY;
|
|
120
|
+
this.classList.add("framv-grabbing");
|
|
121
|
+
this.setPointerCapture(e.pointerId);
|
|
122
|
+
});
|
|
123
|
+
this.addEventListener("pointermove", (e) => {
|
|
124
|
+
if (!this._panning)
|
|
125
|
+
return;
|
|
126
|
+
const dx = e.clientX - this._lastX;
|
|
127
|
+
const dy = e.clientY - this._lastY;
|
|
128
|
+
this._tx += dx;
|
|
129
|
+
this._ty += dy;
|
|
130
|
+
this._lastX = e.clientX;
|
|
131
|
+
this._lastY = e.clientY;
|
|
132
|
+
this._updateTransform();
|
|
133
|
+
});
|
|
134
|
+
this.addEventListener("pointerup", () => {
|
|
135
|
+
this._panning = false;
|
|
136
|
+
this.classList.remove("framv-grabbing");
|
|
137
|
+
});
|
|
138
|
+
this.addEventListener("pointerleave", () => {
|
|
139
|
+
if (this._panning) {
|
|
140
|
+
this._panning = false;
|
|
141
|
+
this.classList.remove("framv-grabbing");
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
attributeChangedCallback(name, _old, value) {
|
|
146
|
+
if (name === "scale" && this._stage) {
|
|
147
|
+
const s = parseFloat(value);
|
|
148
|
+
if (!isNaN(s)) {
|
|
149
|
+
this._scale = Math.min(Math.max(s, this._minScale), this._maxScale);
|
|
150
|
+
this._updateTransform();
|
|
151
|
+
this._updateBadge();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** Pan to center a specific position. */
|
|
156
|
+
centerAt(x, y) {
|
|
157
|
+
const containerW = this.clientWidth || 800;
|
|
158
|
+
const containerH = this.clientHeight || 600;
|
|
159
|
+
this._tx = containerW / 2 - x * this._scale;
|
|
160
|
+
this._ty = containerH / 2 - y * this._scale;
|
|
161
|
+
this._updateTransform();
|
|
162
|
+
}
|
|
163
|
+
/** Reset to initial centered view. */
|
|
164
|
+
reset() {
|
|
165
|
+
this._scale = 1;
|
|
166
|
+
const containerW = this.clientWidth || 800;
|
|
167
|
+
const containerH = this.clientHeight || 600;
|
|
168
|
+
this._tx = (containerW - this.width) / 2;
|
|
169
|
+
this._ty = (containerH - this.height) / 2;
|
|
170
|
+
this._updateTransform();
|
|
171
|
+
this._updateBadge();
|
|
172
|
+
}
|
|
173
|
+
get scale() {
|
|
174
|
+
return this._scale;
|
|
175
|
+
}
|
|
176
|
+
_updateTransform() {
|
|
177
|
+
this._stage.style.transform = `translate(${this._tx}px, ${this._ty}px) scale(${this._scale})`;
|
|
178
|
+
}
|
|
179
|
+
_updateBadge() {
|
|
180
|
+
const badge = this._shadow.querySelector(".framv-canvas-badge");
|
|
181
|
+
if (badge)
|
|
182
|
+
badge.textContent = `${Math.round(this._scale * 100)}%`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (!customElements.get("framv-canvas")) {
|
|
186
|
+
customElements.define("framv-canvas", FramvCanvasElement);
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=element.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element.js","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@framv/canvas",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Infinite canvas component for framv — position elements with zoom and pan",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -b && npm run bundle",
|
|
21
|
+
"prepublishOnly": "npm run build",
|
|
22
|
+
"bundle": "esbuild src/index.ts --bundle --format=esm --outfile=dist/bundle.esm.js && esbuild src/cdn.ts --bundle --format=iife --global-name=FramvCanvas --outfile=dist/bundle.iife.js"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"esbuild": "^0.27.2",
|
|
26
|
+
"typescript": "^5.9.3"
|
|
27
|
+
},
|
|
28
|
+
"author": "Mens Reversa",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/mensreversa/framv.git",
|
|
33
|
+
"directory": "packages/canvas"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/mensreversa/framv/issues"
|
|
37
|
+
}
|
|
38
|
+
}
|