@sunspots/core 0.0.8 → 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/index.d.mts +60 -9
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -5,6 +5,7 @@ declare const Color: {
|
|
|
5
5
|
readonly Transparent: "rgba(0,0,0,0)";
|
|
6
6
|
readonly Black: "#000000";
|
|
7
7
|
readonly White: "#ffffff";
|
|
8
|
+
readonly Primary: "#3b82f6";
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
interface Vector2 {
|
|
@@ -39,6 +40,55 @@ declare enum ResizeDirection {
|
|
|
39
40
|
TopLeft = 7
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
type RightAngleRotation = 0 | 90 | 180 | 270;
|
|
44
|
+
declare function withDpr(value: number): number;
|
|
45
|
+
declare function withPixel(value: number): string;
|
|
46
|
+
declare function withHash(value: string): string;
|
|
47
|
+
declare function randomColor(): string;
|
|
48
|
+
declare function rgbToHex(r: number, g: number, b: number): string;
|
|
49
|
+
declare function rgba<R extends number, G extends number, B extends number, A extends number>(r: R, g: G, b: B, a?: A): `rgba(${R},${G},${B},${A})`;
|
|
50
|
+
declare function angleToRadian(angle: number): number;
|
|
51
|
+
declare function radianToAngle(radian: number): number;
|
|
52
|
+
/**
|
|
53
|
+
* 将点按直角旋转
|
|
54
|
+
* @param origin
|
|
55
|
+
* @param rotation
|
|
56
|
+
* @returns
|
|
57
|
+
*/
|
|
58
|
+
declare function rotatePointRightAngle(origin: Vector2, rotation: RightAngleRotation): Vector2;
|
|
59
|
+
/**
|
|
60
|
+
* 将 world 坐标系中的位移(dx, dy)转换为 local 坐标系中的位移。
|
|
61
|
+
*
|
|
62
|
+
* world 指 canvas 坐标系。
|
|
63
|
+
* local 指以图形左上角为原点,沿图形局部 X/Y 轴方向的坐标系。
|
|
64
|
+
*
|
|
65
|
+
* 由于拖拽/鼠标移动发生在 world 上,做 resize 等操作时常需要转回 local 才能得到沿图形局部轴向的真实位移。
|
|
66
|
+
*
|
|
67
|
+
* @param dx world X
|
|
68
|
+
* @param dy world Y
|
|
69
|
+
* @param rotation
|
|
70
|
+
* @returns
|
|
71
|
+
*/
|
|
72
|
+
declare function worldDeltaToLocalRightAngle(dx: number, dy: number, rotation: RightAngleRotation): Vector2;
|
|
73
|
+
/**
|
|
74
|
+
* 将 local 坐标系中的位移转换为 world 坐标系中的位移。
|
|
75
|
+
*
|
|
76
|
+
* @param dx local X
|
|
77
|
+
* @param dy local Y
|
|
78
|
+
* @param rotation
|
|
79
|
+
* @returns
|
|
80
|
+
*/
|
|
81
|
+
declare function localDeltaToWorldRightAngle(dx: number, dy: number, rotation: RightAngleRotation): Vector2;
|
|
82
|
+
/**
|
|
83
|
+
* 将一个 box 围绕 origin 进行直角旋转后,返回新的 box
|
|
84
|
+
*
|
|
85
|
+
* @param box
|
|
86
|
+
* @param origin
|
|
87
|
+
* @param rotation
|
|
88
|
+
* @returns
|
|
89
|
+
*/
|
|
90
|
+
declare function rotateBoxRightAngle(box: Box, origin: Vector2, rotation: RightAngleRotation): Box;
|
|
91
|
+
|
|
42
92
|
interface StageConfig {
|
|
43
93
|
readonly sceneCanvas: HTMLCanvasElement;
|
|
44
94
|
readonly draggableCanvas: HTMLCanvasElement;
|
|
@@ -60,6 +110,7 @@ declare class Stage {
|
|
|
60
110
|
private draggableContext;
|
|
61
111
|
readonly draftContext: CanvasRenderingContext2D;
|
|
62
112
|
scale: number;
|
|
113
|
+
private snapLines;
|
|
63
114
|
private readonly events;
|
|
64
115
|
private readonly destroyed$;
|
|
65
116
|
constructor(config: StageConfig);
|
|
@@ -78,9 +129,10 @@ declare class Stage {
|
|
|
78
129
|
private drawScene;
|
|
79
130
|
private draw;
|
|
80
131
|
private drawDraggable;
|
|
132
|
+
private drawSnapLines;
|
|
81
133
|
private drawTransformer;
|
|
82
134
|
private drawShadow;
|
|
83
|
-
private
|
|
135
|
+
private getShadowColor;
|
|
84
136
|
private clear;
|
|
85
137
|
private emit;
|
|
86
138
|
on(type: StageEventName): Observable<StageEvent>;
|
|
@@ -98,6 +150,7 @@ declare class Stage {
|
|
|
98
150
|
fill: string | undefined;
|
|
99
151
|
stroke: string | undefined;
|
|
100
152
|
strokeWidth: number;
|
|
153
|
+
rotation: RightAngleRotation;
|
|
101
154
|
} & Record<string, unknown>)[];
|
|
102
155
|
};
|
|
103
156
|
toBlob(quality?: number): Promise<Blob>;
|
|
@@ -111,6 +164,7 @@ interface ShapeConfig {
|
|
|
111
164
|
fill?: string;
|
|
112
165
|
stroke?: string;
|
|
113
166
|
strokeWidth?: number;
|
|
167
|
+
rotation?: number;
|
|
114
168
|
}
|
|
115
169
|
interface ResizableConfig {
|
|
116
170
|
/** 横纵比,输入即代表缩放需要保持横纵比 */
|
|
@@ -137,10 +191,13 @@ declare abstract class Shape<T extends ShapeConfig = ShapeConfig> implements Sha
|
|
|
137
191
|
fill?: string;
|
|
138
192
|
stroke?: string;
|
|
139
193
|
strokeWidth: number;
|
|
194
|
+
rotation: RightAngleRotation;
|
|
140
195
|
constructor(config: T);
|
|
141
196
|
abstract render(context: CanvasRenderingContext2D): void;
|
|
142
197
|
abstract boundingBox(): Box;
|
|
143
198
|
abstract innerBox(): Box;
|
|
199
|
+
worldInnerBox(): Box;
|
|
200
|
+
worldBoundingBox(): Box;
|
|
144
201
|
renderShadow?(context: CanvasRenderingContext2D): void;
|
|
145
202
|
setWidth?(width: number): void;
|
|
146
203
|
setHeight?(height: number): void;
|
|
@@ -159,6 +216,7 @@ declare abstract class Shape<T extends ShapeConfig = ShapeConfig> implements Sha
|
|
|
159
216
|
fill: string | undefined;
|
|
160
217
|
stroke: string | undefined;
|
|
161
218
|
strokeWidth: number;
|
|
219
|
+
rotation: RightAngleRotation;
|
|
162
220
|
} & Record<string, unknown>;
|
|
163
221
|
}
|
|
164
222
|
declare function isLockAspectRatioResize(shape: Shape): shape is Shape & {
|
|
@@ -197,11 +255,4 @@ interface PointerEvent {
|
|
|
197
255
|
offsetY: number;
|
|
198
256
|
}
|
|
199
257
|
|
|
200
|
-
|
|
201
|
-
declare function withPixel(value: number): string;
|
|
202
|
-
declare function withHash(value: string): string;
|
|
203
|
-
declare function randomColor(): string;
|
|
204
|
-
declare function rgbToHex(r: number, g: number, b: number): string;
|
|
205
|
-
declare function rgba<R extends number, G extends number, B extends number, A extends number>(r: R, g: G, b: B, a?: A): `rgba(${R},${G},${B},${A})`;
|
|
206
|
-
|
|
207
|
-
export { type Box, Color, Placement, type PointerEvent, type PointerEventName, ReferenceLine, type ResizableConfig, ResizeDirection, Shape, type ShapeConfig, type ShapeEvent, Stage, type StageConfig, type StageEvent, type StageEventName, type Vector2, isLockAspectRatioResize, randomColor, rgbToHex, rgba, withDpr, withHash, withPixel };
|
|
258
|
+
export { type Box, Color, Placement, type PointerEvent, type PointerEventName, ReferenceLine, type ResizableConfig, ResizeDirection, type RightAngleRotation, Shape, type ShapeConfig, type ShapeEvent, Stage, type StageConfig, type StageEvent, type StageEventName, type Vector2, angleToRadian, isLockAspectRatioResize, localDeltaToWorldRightAngle, radianToAngle, randomColor, rgbToHex, rgba, rotateBoxRightAngle, rotatePointRightAngle, withDpr, withHash, withPixel, worldDeltaToLocalRightAngle };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var U=Object.defineProperty;var f=(c,t)=>U(c,"name",{value:t,configurable:!0});var X="#",J="px";function k(c){return c*devicePixelRatio}f(k,"withDpr");function H(c){return c+J}f(H,"withPixel");function Y(c){return X+c}f(Y,"withHash");function D(){let c=(Math.random()*16777215<<0).toString(16);for(;c.length<6;)c=0+c;return X+c}f(D,"randomColor");function I(c,t,e){return((1<<24)+(c<<16)+(t<<8)+e).toString(16).slice(1)}f(I,"rgbToHex");function N(c,t,e,a=1){return`rgba(${c},${t},${e},${a})`}f(N,"rgba");var E={Transparent:N(0,0,0,0),Black:"#000000",White:"#ffffff"};var F=(e=>(e[e.Horizontal=0]="Horizontal",e[e.Vertical=1]="Vertical",e))(F||{}),W=class W{constructor(t,e){this.placement=t;this.position=e}};f(W,"ReferenceLine");var r=W;var K=(n=>(n[n.Top=0]="Top",n[n.Right=1]="Right",n[n.Bottom=2]="Bottom",n[n.Left=3]="Left",n[n.TopRight=4]="TopRight",n[n.BottomRight=5]="BottomRight",n[n.BottomLeft=6]="BottomLeft",n[n.TopLeft=7]="TopLeft",n))(K||{});import{Subject as Q,filter as Z}from"rxjs";var T=new Map;var O=class O{constructor(t){this.config=t;this.index=0;this.resizable=!0;this.events=new Q;this.strokeWidth=0;for(;;){let e=D();if(e&&!T.has(e)){this.key=e,T.set(e,this);break}}Object.assign(this,t)}get x(){var t;return(t=this.config.x)!=null?t:0}set x(t){this.config.x=t}get y(){var t;return(t=this.config.y)!=null?t:0}set y(t){this.config.y=t}get width(){var t;return(t=this.config.width)!=null?t:0}set width(t){this.config.width=t}get height(){var t;return(t=this.config.height)!=null?t:0}set height(t){this.config.height=t}coord(){return{x:this.x,y:this.y}}emit(t){this.events.next(t)}on(t){return this.events.pipe(Z(e=>e.type===t))}destroy(){this.events.complete()}setAttrs(t){Object.assign(this,t)}toObject(t={}){return Object.assign({type:this.type,index:this.index,x:this.x,y:this.y,width:this.width,height:this.height,fill:this.fill,stroke:this.stroke,strokeWidth:this.strokeWidth},t)}};f(O,"Shape");var L=O;function z(c){return typeof c.resizable=="object"&&!!c.resizable.aspectRatio}f(z,"isLockAspectRatioResize");import{animationFrames as _,filter as R,Subject as G,takeUntil as M}from"rxjs";var j=class j extends L{constructor(e){super({fill:"#ffffff",stroke:"#3b82f6",strokeWidth:2});this.direction=e;this.type="anchor";this.radius=5}getRadius(){return this.radius/this.stage.scale}render(e){let{x:a,y:h,stroke:w,strokeWidth:u}=this;e.beginPath(),e.arc(a,h,this.getRadius(),0,Math.PI*2,!1),e.fill(),w&&(e.lineWidth=(u!=null?u:1)/this.stage.scale,e.stroke()),e.closePath()}innerBox(){return{x:this.x-this.getRadius(),y:this.y-this.getRadius(),width:this.getRadius()*2,height:this.getRadius()*2}}boundingBox(){var w;let e=this.innerBox(),a=(w=this.strokeWidth)!=null?w:0,h=a/2;return e.x-=h,e.y-=h,e.width+=a,e.height+=a,e}setWidth(e){this.width=e,this.radius=e/2}setHeight(e){this.height=e,this.radius=e/2}get x(){let e=this.target.boundingBox();switch(this.direction){case 0:case 2:return e.x+e.width/2;case 4:case 1:case 5:return e.x+e.width;case 7:case 6:case 3:return e.x}}set x(e){}get y(){let e=this.target.boundingBox();switch(this.direction){case 7:case 0:case 4:return e.y;case 1:case 3:return e.y+e.height/2;case 5:case 2:case 6:return e.y+e.height}}set y(e){}setTarget(e){this.target=e}};f(j,"Anchor");var b=j;var $=class ${constructor(t){this.config=t;this.anchors=[new b(7),new b(0),new b(4),new b(1),new b(5),new b(2),new b(6),new b(3)];this.shapes=[];this.activatedShape=null;this.scale=1;this.events=new G;this.destroyed$=new G;let{sceneCanvas:e,shadowCanvas:a,draggableCanvas:h,draftCanvas:w,canvasEvents:u,clientEvents:y}=t;this.context=e.getContext("2d"),this.shadowContext=a.getContext("2d",{willReadFrequently:!0}),this.draggableContext=h.getContext("2d"),this.draftContext=w.getContext("2d");for(let g of this.anchors)g.stage=this;this.resize();let n,l,s,x,A=!1;u.pipe(R(g=>g.type==="pointerdown"),M(this.destroyed$)).subscribe(g=>{if(g.button!==void 0&&g.button!==0)return;A=!0,n=g.offsetX,l=g.offsetY;let P=k(g.offsetX),V=k(g.offsetY),m=this.getColor(P,V),o=T.get(m);if(!o){this.emit({type:"pointerdown"}),this.setActivatedShape(null);return}if(this.activatedShape=o,o.emit({type:"pointerdown"}),o instanceof b){s=o.target.innerBox(),x=o.target.coord(),this.drawScene();return}this.setActivatedShape(o),this.emit({type:"pointerdown",target:o}),s=o.innerBox(),x=o.coord(),this.drawDraggable(),this.drawScene()}),y.pipe(R(g=>g.type==="pointermove"),R(()=>A),M(this.destroyed$)).subscribe(g=>{let P=g.offsetX,V=g.offsetY,m=(P-n)/this.scale,o=(V-l)/this.scale;if(this.activatedShape instanceof b){let B=this.activatedShape,d=B.target,v=x.x,S=x.y,p=s.width,i=s.height;switch(B.direction){case 7:v=x.x+m,S=x.y+o,i=s.height-o,p=s.width-m;break;case 0:S=x.y+o,i=s.height-o,z(d)&&(p=i*d.resizable.aspectRatio);break;case 4:S=x.y+o,i=s.height-o,p=s.width+m;break;case 1:p=s.width+m,z(d)&&(i=p/d.resizable.aspectRatio);break;case 5:p=s.width+m,i=s.height+o;break;case 2:i=s.height+o,z(d)&&(p=i*d.resizable.aspectRatio);break;case 6:i=s.height+o,v=x.x+m,p=s.width-m;break;case 3:v=x.x+m,p=s.width-m,z(d)&&(i=p/d.resizable.aspectRatio);break}v=Math.round(v),S=Math.round(S),p=Math.round(p),i=Math.round(i),d.x=Math.min(x.x+s.width,v),d.y=Math.min(x.y+s.height,S),d.setWidth?d.setWidth(Math.max(1,p)):d.width=Math.max(1,p),d.setHeight?d.setHeight(Math.max(1,i)):d.height=Math.max(1,i)}else if(this.activatedShape){let B=Math.round(x.x+m),d=Math.round(x.y+o),v=1/0,S=1/0,p=[new r(0,0),new r(1,0),new r(0,this.config.height/2),new r(1,this.config.width/2),new r(0,this.config.height/2-this.activatedShape.height/2),new r(1,this.config.width/2-this.activatedShape.width/2),new r(0,this.config.height-this.activatedShape.height),new r(1,this.config.width-this.activatedShape.width)];for(let i of this.shapes)i!==this.activatedShape&&p.push(new r(0,i.y-this.activatedShape.height),i.height>this.activatedShape.height?new r(0,i.y-this.activatedShape.height/2):new r(0,i.y-this.activatedShape.height+i.height/2),new r(0,i.y),i.height>this.activatedShape.height?new r(0,i.y+i.height-this.activatedShape.height/2):new r(0,i.y-this.activatedShape.height+i.height),new r(0,i.y/2),new r(0,i.y+i.height),new r(1,i.x-this.activatedShape.width),i.width>this.activatedShape.width?new r(1,i.x-this.activatedShape.width/2):new r(1,i.x-this.activatedShape.width+i.width/2),new r(1,i.x),i.width>this.activatedShape.width?new r(1,i.x+i.width-this.activatedShape.width/2):new r(1,i.x-this.activatedShape.width+i.width),new r(1,i.x/2),new r(1,i.x+i.width));for(let i of p)switch(i.placement){case 0:{let C=Math.abs(i.position-d);C<=4&&C<S&&(d=i.position,S=C);break}case 1:{let C=Math.abs(i.position-B);C<=4&&C<v&&(B=i.position,v=C);break}}this.activatedShape.x=B,this.activatedShape.y=d}}),y.pipe(R(g=>g.type==="pointerup"||g.type==="pointercancel"),M(this.destroyed$)).subscribe(()=>{this.render(),A=!1}),_().pipe(R(()=>A&&!!this.activatedShape),M(this.destroyed$)).subscribe(()=>{this.drawDraggable()})}resize(t){Object.assign(this.config,t);let{sceneCanvas:e,shadowCanvas:a,draggableCanvas:h,draftCanvas:w,width:u,height:y,dpr:n}=this.config;for(let l of[e,a,h,w]){let s=l.getContext("2d");l.style.width=H(u),l.style.height=H(y),l.width=k(u),l.height=k(y),s.scale(n,n)}}zoom(t){let{sceneCanvas:e,shadowCanvas:a,draggableCanvas:h,draftCanvas:w,dpr:u,width:y,height:n}=this.config;for(let l of[e,a,h,w]){let s=l.getContext("2d");l.style.width=H(y*t),l.style.height=H(n*t),l.width=k(y*t),l.height=k(n*t),s.scale(u*t,u*t)}this.scale=t}add(...t){for(let e of t)e.index=this.shapes.length,e.stage=this,this.shapes.push(e),this.draw(e),this.emit({type:"add",target:e})}remove(...t){let e=this.getActivatedShape();for(let a of t){this.shapes.splice(this.shapes.indexOf(a),1);for(let h of this.shapes)h.index>a.index&&h.index--;e===a&&this.setActivatedShape(null),this.emit({type:"remove",target:a})}for(let a=0;a<this.shapes.length;a++){let h=this.shapes[a];h.index=a}}setActivatedShape(t){if(!t){this.activatedShape=null;return}for(let e of this.shapes)e.index>t.index&&e.index--;t.index=this.shapes.length;for(let e of this.anchors)e.target=t;this.activatedShape=t}getActivatedShape(){return this.activatedShape instanceof b?this.activatedShape.target:this.activatedShape}render(){this.activatedShape?this.drawDraggable():this.clear(this.draggableContext),this.drawScene()}isActivatedShape(t){let e=this.getActivatedShape();return t===e}drawScene(){this.clear(this.context),this.clear(this.shadowContext);for(let e of this.shapes.slice().sort((a,h)=>a.index-h.index))this.draw(e);let t=this.getActivatedShape();if(t&&t.resizable)for(let e of this.anchors)this.drawShadow(e)}draw(t){var e;this.drawShadow(t),!this.isActivatedShape(t)&&(this.context.save(),this.context.fillStyle=(e=t.fill)!=null?e:E.Transparent,t.stroke&&(this.context.lineWidth=t.strokeWidth,this.context.strokeStyle=t.stroke),this.context.beginPath(),t.render(this.context),this.context.stroke(),this.context.restore())}drawDraggable(){var e;let t=this.getActivatedShape();t&&(this.clear(this.draggableContext),this.draggableContext.save(),this.draggableContext.fillStyle=(e=t.fill)!=null?e:E.Transparent,t.stroke&&(this.draggableContext.lineWidth=t.strokeWidth,this.draggableContext.strokeStyle=t.stroke),this.draggableContext.beginPath(),t.render(this.draggableContext),this.draggableContext.stroke(),this.draggableContext.restore(),this.drawTransformer(t))}drawTransformer(t){let e=t.boundingBox();if(this.draggableContext.fillStyle="#ffffff",this.draggableContext.strokeStyle="#3b82f6",this.draggableContext.lineWidth=2/this.scale,this.draggableContext.strokeRect(e.x,e.y,e.width,e.height),!t.resizable)return;let a=[];typeof t.resizable=="object"&&(t.resizable.aspectRatio?a=[0,1,2,3]:t.resizable.directions&&(a=t.resizable.directions));for(let h of this.anchors)a.length&&!a.includes(h.direction)||h.render(this.draggableContext)}drawShadow(t){this.shadowContext.save(),this.shadowContext.fillStyle=t.fill?t.key:E.Transparent,this.shadowContext.strokeStyle=t.key,t.stroke&&(this.shadowContext.lineWidth=t.strokeWidth),this.shadowContext.beginPath(),t.renderShadow?t.renderShadow(this.shadowContext):t.render(this.shadowContext),this.shadowContext.stroke(),this.shadowContext.restore()}getColor(t,e){let{data:a}=this.shadowContext.getImageData(t,e,1,1);return Y(I(a[0],a[1],a[2]))}clear(t){t.clearRect(0,0,this.config.width,this.config.height)}emit(t){this.events.next(t)}on(t){return this.events.pipe(R(e=>e.type===t))}destroy(){this.destroyed$.next(),this.destroyed$.complete(),this.events.complete();for(let t of this.shapes)t.destroy()}toObject(){return{width:this.config.width,height:this.config.height,children:this.shapes.map(t=>t.toObject())}}toBlob(t=1){return this.setActivatedShape(null),this.render(),new Promise(e=>{this.config.sceneCanvas.toBlob(a=>e(a),"image/webp",t)})}};f($,"Stage");var q=$;export{E as Color,F as Placement,r as ReferenceLine,K as ResizeDirection,L as Shape,q as Stage,z as isLockAspectRatioResize,D as randomColor,I as rgbToHex,N as rgba,k as withDpr,Y as withHash,H as withPixel};
|
|
1
|
+
var it=Object.defineProperty;var tt=Object.getOwnPropertySymbols;var pt=Object.prototype.hasOwnProperty,xt=Object.prototype.propertyIsEnumerable;var et=(i,t,e)=>t in i?it(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,nt=(i,t)=>{for(var e in t||(t={}))pt.call(t,e)&&et(i,e,t[e]);if(tt)for(var e of tt(t))xt.call(t,e)&&et(i,e,t[e]);return i};var f=(i,t)=>it(i,"name",{value:t,configurable:!0});var ot="#",ut="px";function A(i){return i*devicePixelRatio}f(A,"withDpr");function V(i){return i+ut}f(V,"withPixel");function rt(i){return ot+i}f(rt,"withHash");function st(){let i=(Math.random()*16777215<<0).toString(16);for(;i.length<6;)i=0+i;return ot+i}f(st,"randomColor");function at(i,t,e){return((1<<24)+(i<<16)+(t<<8)+e).toString(16).slice(1)}f(at,"rgbToHex");function ht(i,t,e,n=1){return`rgba(${i},${t},${e},${n})`}f(ht,"rgba");function Y(i){return i*Math.PI/180}f(Y,"angleToRadian");function St(i){return i*180/Math.PI}f(St,"radianToAngle");function U(i,t){switch(t){case 90:return{x:-i.y,y:i.x};case 180:return{x:-i.x,y:-i.y};case 270:return{x:i.y,y:-i.x};default:return i}}f(U,"rotatePointRightAngle");function ct(i,t,e){switch(e){case 90:return{x:t,y:-i};case 180:return{x:-i,y:-t};case 270:return{x:-t,y:i};default:return{x:i,y:t}}}f(ct,"worldDeltaToLocalRightAngle");function dt(i,t,e){switch(e){case 90:return{x:-t,y:i};case 180:return{x:-i,y:-t};case 270:return{x:t,y:-i};default:return{x:i,y:t}}}f(dt,"localDeltaToWorldRightAngle");function J(i,t,e){if(e===0)return nt({},i);let n=[{x:i.x,y:i.y},{x:i.x+i.width,y:i.y},{x:i.x,y:i.y+i.height},{x:i.x+i.width,y:i.y+i.height}],s=1/0,c=1/0,h=-1/0,d=-1/0;for(let o of n){let a={x:o.x-t.x,y:o.y-t.y},r=U(a,e),B={x:t.x+r.x,y:t.y+r.y};s=Math.min(s,B.x),c=Math.min(c,B.y),h=Math.max(h,B.x),d=Math.max(d,B.y)}return{x:s,y:c,width:h-s,height:d-c}}f(J,"rotateBoxRightAngle");var T={Transparent:ht(0,0,0,0),Black:"#000000",White:"#ffffff",Primary:"#3b82f6"};var lt=(e=>(e[e.Horizontal=0]="Horizontal",e[e.Vertical=1]="Vertical",e))(lt||{}),K=class K{constructor(t,e){this.placement=t;this.position=e}};f(K,"ReferenceLine");var y=K;var mt=(o=>(o[o.Top=0]="Top",o[o.Right=1]="Right",o[o.Bottom=2]="Bottom",o[o.Left=3]="Left",o[o.TopRight=4]="TopRight",o[o.BottomRight=5]="BottomRight",o[o.BottomLeft=6]="BottomLeft",o[o.TopLeft=7]="TopLeft",o))(mt||{});import{filter as bt,Subject as yt}from"rxjs";var z=new Map;var Q=class Q{constructor(t){this.config=t;this.index=0;this.resizable=!0;this.events=new yt;this.strokeWidth=0;this.rotation=0;for(;;){let e=st();if(e&&!z.has(e)){this.key=e,z.set(e,this);break}}Object.assign(this,t)}get x(){var t;return(t=this.config.x)!=null?t:0}set x(t){this.config.x=t}get y(){var t;return(t=this.config.y)!=null?t:0}set y(t){this.config.y=t}get width(){var t;return(t=this.config.width)!=null?t:0}set width(t){this.config.width=t}get height(){var t;return(t=this.config.height)!=null?t:0}set height(t){this.config.height=t}worldInnerBox(){return J(this.innerBox(),{x:this.x,y:this.y},this.rotation)}worldBoundingBox(){return J(this.boundingBox(),{x:this.x,y:this.y},this.rotation)}coord(){return{x:this.x,y:this.y}}emit(t){this.events.next(t)}on(t){return this.events.pipe(bt(e=>e.type===t))}destroy(){this.events.complete()}setAttrs(t){Object.assign(this,t)}toObject(t={}){return Object.assign({type:this.type,index:this.index,x:this.x,y:this.y,width:this.width,height:this.height,fill:this.fill,stroke:this.stroke,strokeWidth:this.strokeWidth,rotation:this.rotation},t)}};f(Q,"Shape");var I=Q;function X(i){return typeof i.resizable=="object"&&!!i.resizable.aspectRatio}f(X,"isLockAspectRatioResize");import{animationFrames as wt,filter as P,Subject as gt,takeUntil as j}from"rxjs";var Z=class Z extends I{constructor(e){super({fill:T.White,stroke:T.Primary,strokeWidth:2});this.direction=e;this.type="anchor";this.radius=5}getAnchorLocalPoint(e,n){switch(this.direction){case 7:return{x:0,y:0};case 0:return{x:e/2,y:0};case 4:return{x:e,y:0};case 1:return{x:e,y:n/2};case 5:return{x:e,y:n};case 2:return{x:e/2,y:n};case 6:return{x:0,y:n};case 3:return{x:0,y:n/2}}}getAnchorWorldPoint(){let e=this.target.boundingBox(),{rotation:n}=this.target;if(!n){let a,r;switch(this.direction){case 0:case 2:a=e.x+e.width/2;break;case 4:case 1:case 5:a=e.x+e.width;break;case 7:case 6:case 3:a=e.x;break}switch(this.direction){case 7:case 0:case 4:r=e.y;break;case 1:case 3:r=e.y+e.height/2;break;case 5:case 2:case 6:r=e.y+e.height;break}return{x:a,y:r}}let s=e.x-this.target.x,c=e.y-this.target.y,h=this.getAnchorLocalPoint(e.width,e.height),d={x:s+h.x,y:c+h.y},o=U(d,n);return{x:this.target.x+o.x,y:this.target.y+o.y}}getRadius(){return this.radius/this.stage.scale}render(e){let{x:n,y:s,stroke:c,rotation:h,strokeWidth:d}=this;e.save(),h&&(e.translate(n,s),e.rotate(Y(h))),e.beginPath(),e.arc(h?0:n,h?0:s,this.getRadius(),0,Math.PI*2,!1),e.fill(),c&&(e.lineWidth=(d!=null?d:1)/this.stage.scale,e.stroke()),e.closePath(),e.restore()}innerBox(){return{x:this.x-this.getRadius(),y:this.y-this.getRadius(),width:this.getRadius()*2,height:this.getRadius()*2}}boundingBox(){var c;let e=this.innerBox(),n=(c=this.strokeWidth)!=null?c:0,s=n/2;return e.x-=s,e.y-=s,e.width+=n,e.height+=n,e}setWidth(e){this.width=e,this.radius=e/2}setHeight(e){this.height=e,this.radius=e/2}get x(){return this.getAnchorWorldPoint().x}set x(e){}get y(){return this.getAnchorWorldPoint().y}set y(e){}setTarget(e){this.target=e}};f(Z,"Anchor");var v=Z;var _=class _{constructor(t){this.config=t;this.anchors=[new v(7),new v(0),new v(4),new v(1),new v(5),new v(2),new v(6),new v(3)];this.shapes=[];this.activatedShape=null;this.scale=1;this.snapLines=null;this.events=new gt;this.destroyed$=new gt;let{sceneCanvas:e,shadowCanvas:n,draggableCanvas:s,draftCanvas:c,canvasEvents:h,clientEvents:d}=t;this.context=e.getContext("2d"),this.shadowContext=n.getContext("2d",{willReadFrequently:!0}),this.draggableContext=s.getContext("2d"),this.draftContext=c.getContext("2d");for(let u of this.anchors)u.stage=this;this.resize();let o,a,r,B,D=!1;h.pipe(P(u=>u.type==="pointerdown"),j(this.destroyed$)).subscribe(u=>{if(u.button!==void 0&&u.button!==0)return;D=!0,o=u.offsetX,a=u.offsetY;let $=A(u.offsetX),N=A(u.offsetY),O=this.getShadowColor($,N),S=z.get(O);if(!S){this.emit({type:"pointerdown"}),this.setActivatedShape(null);return}if(this.activatedShape=S,S.emit({type:"pointerdown"}),S instanceof v){r=S.target.innerBox(),B=S.target.coord(),this.drawScene();return}this.setActivatedShape(S),this.emit({type:"pointerdown",target:S}),r=S.innerBox(),B=S.coord(),this.drawDraggable(),this.drawScene()}),d.pipe(P(u=>u.type==="pointermove"),P(()=>D),j(this.destroyed$)).subscribe(u=>{let $=u.offsetX,N=u.offsetY,O=($-o)/this.scale,S=(N-a)/this.scale;if(this.activatedShape instanceof v){this.snapLines=null;let C=this.activatedShape,l=C.target,{rotation:W}=l,H=ct(O,S,W),p=H.x,R=H.y,k=0,w=0,g=r.width,x=r.height;switch(C.direction){case 7:k=p,w=R,x=r.height-R,g=r.width-p;break;case 0:w=R,x=r.height-R,X(l)&&(g=x*l.resizable.aspectRatio);break;case 4:w=R,x=r.height-R,g=r.width+p;break;case 1:g=r.width+p,X(l)&&(x=g/l.resizable.aspectRatio);break;case 5:g=r.width+p,x=r.height+R;break;case 2:x=r.height+R,X(l)&&(g=x*l.resizable.aspectRatio);break;case 6:x=r.height+R,k=p,g=r.width-p;break;case 3:k=p,g=r.width-p,X(l)&&(x=g/l.resizable.aspectRatio);break}let M=1,b=1;(C.direction===7||C.direction===3||C.direction===6)&&(k=Math.min(k,r.width-M)),(C.direction===7||C.direction===0||C.direction===4)&&(w=Math.min(w,r.height-b)),g=Math.max(M,g),x=Math.max(b,x),k=Math.round(k),w=Math.round(w),g=Math.round(g),x=Math.round(x);let m=dt(k,w,W);l.x=Math.round(B.x+m.x),l.y=Math.round(B.y+m.y),l.setWidth?l.setWidth(Math.max(1,g)):l.width=Math.max(1,g),l.setHeight?l.setHeight(Math.max(1,x)):l.height=Math.max(1,x)}else if(this.activatedShape){let C=Math.round(B.x+O),l=Math.round(B.y+S),W=1/0,H=1/0;this.activatedShape.x=C,this.activatedShape.y=l;let p=this.activatedShape.worldBoundingBox(),R=[new y(0,0),new y(0,this.config.height/2),new y(0,this.config.height),new y(1,0),new y(1,this.config.width/2),new y(1,this.config.width)];for(let b of this.shapes){if(b===this.activatedShape)continue;let m=b.worldBoundingBox();R.push(new y(0,m.y),new y(0,m.y+m.height/2),new y(0,m.y+m.height),new y(1,m.x),new y(1,m.x+m.width/2),new y(1,m.x+m.width))}let k=2/this.scale,w=0,g=0,x,M;for(let b of R)switch(b.placement){case 0:{let m=p.y+g,F=p.y+p.height/2+g,G=p.y+p.height+g,q=[b.position-m,b.position-F,b.position-G];for(let E of q){let L=Math.abs(E);L<=k&&L<H&&(g=E,H=L,M=b.position)}break}case 1:{let m=p.x+w,F=p.x+p.width/2+w,G=p.x+p.width+w,q=[b.position-m,b.position-F,b.position-G];for(let E of q){let L=Math.abs(E);L<=k&&L<W&&(w=E,W=L,x=b.position)}break}}C=Math.round(C+w),l=Math.round(l+g),this.snapLines=x!==void 0||M!==void 0?{x,y:M}:null,this.activatedShape.x=C,this.activatedShape.y=l}}),d.pipe(P(u=>u.type==="pointerup"||u.type==="pointercancel"),j(this.destroyed$)).subscribe(()=>{D=!1,this.snapLines=null,this.render()}),wt().pipe(P(()=>D&&!!this.activatedShape),j(this.destroyed$)).subscribe(()=>{this.drawDraggable()})}resize(t){Object.assign(this.config,t);let{sceneCanvas:e,shadowCanvas:n,draggableCanvas:s,draftCanvas:c,width:h,height:d,dpr:o}=this.config;for(let a of[e,n,s,c]){let r=a.getContext("2d");a.style.width=V(h),a.style.height=V(d),a.width=A(h),a.height=A(d),r.scale(o,o)}}zoom(t){let{sceneCanvas:e,shadowCanvas:n,draggableCanvas:s,draftCanvas:c,dpr:h,width:d,height:o}=this.config;for(let a of[e,n,s,c]){let r=a.getContext("2d");a.style.width=V(d*t),a.style.height=V(o*t),a.width=A(d*t),a.height=A(o*t),r.scale(h*t,h*t)}this.scale=t}add(...t){for(let e of t)e.index=this.shapes.length,e.stage=this,this.shapes.push(e),this.draw(e),this.emit({type:"add",target:e})}remove(...t){let e=this.getActivatedShape();for(let n of t){this.shapes.splice(this.shapes.indexOf(n),1);for(let s of this.shapes)s.index>n.index&&s.index--;e===n&&this.setActivatedShape(null),this.emit({type:"remove",target:n})}for(let n=0;n<this.shapes.length;n++){let s=this.shapes[n];s.index=n}}setActivatedShape(t){if(!t){this.activatedShape=null;return}for(let e of this.shapes)e.index>t.index&&e.index--;t.index=this.shapes.length;for(let e of this.anchors)e.target=t;this.activatedShape=t}getActivatedShape(){return this.activatedShape instanceof v?this.activatedShape.target:this.activatedShape}render(){this.activatedShape?this.drawDraggable():this.clear(this.draggableContext),this.drawScene()}isActivatedShape(t){let e=this.getActivatedShape();return t===e}drawScene(){this.clear(this.context),this.clear(this.shadowContext);for(let e of this.shapes.slice().sort((n,s)=>n.index-s.index))this.draw(e);let t=this.getActivatedShape();if(t&&t.resizable)for(let e of this.anchors)this.drawShadow(e)}draw(t){var e;this.drawShadow(t),!this.isActivatedShape(t)&&(this.context.save(),this.context.fillStyle=(e=t.fill)!=null?e:T.Transparent,t.stroke&&(this.context.lineWidth=t.strokeWidth,this.context.strokeStyle=t.stroke),this.context.beginPath(),t.render(this.context),this.context.stroke(),this.context.restore())}drawDraggable(){var n;let t=this.getActivatedShape(),e=this.draggableContext;t&&(this.clear(e),e.save(),e.fillStyle=(n=t.fill)!=null?n:T.Transparent,t.stroke&&(e.lineWidth=t.strokeWidth,e.strokeStyle=t.stroke),e.beginPath(),t.render(e),e.stroke(),e.restore(),this.drawTransformer(t),this.drawSnapLines())}drawSnapLines(){if(!this.snapLines)return;let t=this.draggableContext,{x:e,y:n}=this.snapLines;t.save(),t.strokeStyle=T.Primary,t.lineWidth=.5/this.scale,n!==void 0&&(t.beginPath(),t.moveTo(0,n),t.lineTo(this.config.width,n),t.stroke()),e!==void 0&&(t.beginPath(),t.moveTo(e,0),t.lineTo(e,this.config.height),t.stroke()),t.restore()}drawTransformer(t){var o;let e=this.draggableContext,{x:n,y:s,rotation:c}=t,h=t.boundingBox();if(e.save(),c&&(e.translate(n,s),e.rotate(Y(c))),e.fillStyle=T.White,e.strokeStyle=T.Primary,e.lineWidth=2/this.scale,e.strokeRect(c?h.x-n:h.x,c?h.y-s:h.y,h.width,h.height),e.restore(),!t.resizable)return;let d=[];typeof t.resizable=="object"&&(t.resizable.aspectRatio?d=[0,1,2,3]:t.resizable.directions&&(d=t.resizable.directions));for(let a of this.anchors)d.length&&!d.includes(a.direction)||(e.fillStyle=(o=a.fill)!=null?o:T.Transparent,e.strokeStyle=a.stroke,a.rotation=c,a.render(e))}drawShadow(t){var n;let e=this.shadowContext;e.fillStyle=t.fill?t.key:T.Transparent,e.strokeStyle=t.key,t.stroke&&(e.lineWidth=t.strokeWidth),e.beginPath(),((n=t.renderShadow)!=null?n:t.render).call(t,e),e.stroke()}getShadowColor(t,e){let{data:n}=this.shadowContext.getImageData(t,e,1,1);return rt(at(n[0],n[1],n[2]))}clear(t){t.clearRect(0,0,this.config.width,this.config.height)}emit(t){this.events.next(t)}on(t){return this.events.pipe(P(e=>e.type===t))}destroy(){this.destroyed$.next(),this.destroyed$.complete(),this.events.complete();for(let t of this.shapes)t.destroy()}toObject(){return{width:this.config.width,height:this.config.height,children:this.shapes.map(t=>t.toObject())}}toBlob(t=1){return this.setActivatedShape(null),this.render(),new Promise(e=>{this.config.sceneCanvas.toBlob(n=>e(n),"image/webp",t)})}};f(_,"Stage");var ft=_;export{T as Color,lt as Placement,y as ReferenceLine,mt as ResizeDirection,I as Shape,ft as Stage,Y as angleToRadian,X as isLockAspectRatioResize,dt as localDeltaToWorldRightAngle,St as radianToAngle,st as randomColor,at as rgbToHex,ht as rgba,J as rotateBoxRightAngle,U as rotatePointRightAngle,A as withDpr,rt as withHash,V as withPixel,ct as worldDeltaToLocalRightAngle};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sunspots/core",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.mts",
|
|
@@ -28,5 +28,5 @@
|
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"rxjs": "^7.8.1"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "1abe322b4ed0bfd15e92931d44a5c2350bdb986e"
|
|
32
32
|
}
|