@sunspots/core 0.0.8 → 0.1.1
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 +64 -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,59 @@ declare enum ResizeDirection {
|
|
|
39
40
|
TopLeft = 7
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
declare function pixelToDot(px: number): number;
|
|
44
|
+
declare function dotToPixel(dot: number): number;
|
|
45
|
+
declare function millimeterToPixel(mm: number): number;
|
|
46
|
+
declare function pixelToMillimeter(px: number): number;
|
|
47
|
+
type RightAngleRotation = 0 | 90 | 180 | 270;
|
|
48
|
+
declare function withDpr(value: number): number;
|
|
49
|
+
declare function withPixel(value: number): string;
|
|
50
|
+
declare function withHash(value: string): string;
|
|
51
|
+
declare function randomColor(): string;
|
|
52
|
+
declare function rgbToHex(r: number, g: number, b: number): string;
|
|
53
|
+
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})`;
|
|
54
|
+
declare function angleToRadian(angle: number): number;
|
|
55
|
+
declare function radianToAngle(radian: number): number;
|
|
56
|
+
/**
|
|
57
|
+
* 将点按直角旋转
|
|
58
|
+
* @param origin
|
|
59
|
+
* @param rotation
|
|
60
|
+
* @returns
|
|
61
|
+
*/
|
|
62
|
+
declare function rotatePointRightAngle(origin: Vector2, rotation: RightAngleRotation): Vector2;
|
|
63
|
+
/**
|
|
64
|
+
* 将 world 坐标系中的位移(dx, dy)转换为 local 坐标系中的位移。
|
|
65
|
+
*
|
|
66
|
+
* world 指 canvas 坐标系。
|
|
67
|
+
* local 指以图形左上角为原点,沿图形局部 X/Y 轴方向的坐标系。
|
|
68
|
+
*
|
|
69
|
+
* 由于拖拽/鼠标移动发生在 world 上,做 resize 等操作时常需要转回 local 才能得到沿图形局部轴向的真实位移。
|
|
70
|
+
*
|
|
71
|
+
* @param dx world X
|
|
72
|
+
* @param dy world Y
|
|
73
|
+
* @param rotation
|
|
74
|
+
* @returns
|
|
75
|
+
*/
|
|
76
|
+
declare function worldDeltaToLocalRightAngle(dx: number, dy: number, rotation: RightAngleRotation): Vector2;
|
|
77
|
+
/**
|
|
78
|
+
* 将 local 坐标系中的位移转换为 world 坐标系中的位移。
|
|
79
|
+
*
|
|
80
|
+
* @param dx local X
|
|
81
|
+
* @param dy local Y
|
|
82
|
+
* @param rotation
|
|
83
|
+
* @returns
|
|
84
|
+
*/
|
|
85
|
+
declare function localDeltaToWorldRightAngle(dx: number, dy: number, rotation: RightAngleRotation): Vector2;
|
|
86
|
+
/**
|
|
87
|
+
* 将一个 box 围绕 origin 进行直角旋转后,返回新的 box
|
|
88
|
+
*
|
|
89
|
+
* @param box
|
|
90
|
+
* @param origin
|
|
91
|
+
* @param rotation
|
|
92
|
+
* @returns
|
|
93
|
+
*/
|
|
94
|
+
declare function rotateBoxRightAngle(box: Box, origin: Vector2, rotation: RightAngleRotation): Box;
|
|
95
|
+
|
|
42
96
|
interface StageConfig {
|
|
43
97
|
readonly sceneCanvas: HTMLCanvasElement;
|
|
44
98
|
readonly draggableCanvas: HTMLCanvasElement;
|
|
@@ -60,6 +114,7 @@ declare class Stage {
|
|
|
60
114
|
private draggableContext;
|
|
61
115
|
readonly draftContext: CanvasRenderingContext2D;
|
|
62
116
|
scale: number;
|
|
117
|
+
private snapLines;
|
|
63
118
|
private readonly events;
|
|
64
119
|
private readonly destroyed$;
|
|
65
120
|
constructor(config: StageConfig);
|
|
@@ -78,9 +133,10 @@ declare class Stage {
|
|
|
78
133
|
private drawScene;
|
|
79
134
|
private draw;
|
|
80
135
|
private drawDraggable;
|
|
136
|
+
private drawSnapLines;
|
|
81
137
|
private drawTransformer;
|
|
82
138
|
private drawShadow;
|
|
83
|
-
private
|
|
139
|
+
private getShadowColor;
|
|
84
140
|
private clear;
|
|
85
141
|
private emit;
|
|
86
142
|
on(type: StageEventName): Observable<StageEvent>;
|
|
@@ -98,6 +154,7 @@ declare class Stage {
|
|
|
98
154
|
fill: string | undefined;
|
|
99
155
|
stroke: string | undefined;
|
|
100
156
|
strokeWidth: number;
|
|
157
|
+
rotation: RightAngleRotation;
|
|
101
158
|
} & Record<string, unknown>)[];
|
|
102
159
|
};
|
|
103
160
|
toBlob(quality?: number): Promise<Blob>;
|
|
@@ -111,6 +168,7 @@ interface ShapeConfig {
|
|
|
111
168
|
fill?: string;
|
|
112
169
|
stroke?: string;
|
|
113
170
|
strokeWidth?: number;
|
|
171
|
+
rotation?: number;
|
|
114
172
|
}
|
|
115
173
|
interface ResizableConfig {
|
|
116
174
|
/** 横纵比,输入即代表缩放需要保持横纵比 */
|
|
@@ -137,10 +195,13 @@ declare abstract class Shape<T extends ShapeConfig = ShapeConfig> implements Sha
|
|
|
137
195
|
fill?: string;
|
|
138
196
|
stroke?: string;
|
|
139
197
|
strokeWidth: number;
|
|
198
|
+
rotation: RightAngleRotation;
|
|
140
199
|
constructor(config: T);
|
|
141
200
|
abstract render(context: CanvasRenderingContext2D): void;
|
|
142
201
|
abstract boundingBox(): Box;
|
|
143
202
|
abstract innerBox(): Box;
|
|
203
|
+
worldInnerBox(): Box;
|
|
204
|
+
worldBoundingBox(): Box;
|
|
144
205
|
renderShadow?(context: CanvasRenderingContext2D): void;
|
|
145
206
|
setWidth?(width: number): void;
|
|
146
207
|
setHeight?(height: number): void;
|
|
@@ -159,6 +220,7 @@ declare abstract class Shape<T extends ShapeConfig = ShapeConfig> implements Sha
|
|
|
159
220
|
fill: string | undefined;
|
|
160
221
|
stroke: string | undefined;
|
|
161
222
|
strokeWidth: number;
|
|
223
|
+
rotation: RightAngleRotation;
|
|
162
224
|
} & Record<string, unknown>;
|
|
163
225
|
}
|
|
164
226
|
declare function isLockAspectRatioResize(shape: Shape): shape is Shape & {
|
|
@@ -197,11 +259,4 @@ interface PointerEvent {
|
|
|
197
259
|
offsetY: number;
|
|
198
260
|
}
|
|
199
261
|
|
|
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 };
|
|
262
|
+
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, dotToPixel, isLockAspectRatioResize, localDeltaToWorldRightAngle, millimeterToPixel, pixelToDot, pixelToMillimeter, 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,ut=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))ut.call(t,e)&&et(i,e,t[e]);return i};var c=(i,t)=>it(i,"name",{value:t,configurable:!0});var ot="#",xt="px";function St(i){return Math.round(i*.8)}c(St,"pixelToDot");function Ct(i){return Math.round(i/.8)}c(Ct,"dotToPixel");function Rt(i){return i*10}c(Rt,"millimeterToPixel");function Bt(i){return i/10}c(Bt,"pixelToMillimeter");function L(i){return i*devicePixelRatio}c(L,"withDpr");function z(i){return i+xt}c(z,"withPixel");function rt(i){return ot+i}c(rt,"withHash");function at(){let i=(Math.random()*16777215<<0).toString(16);for(;i.length<6;)i=0+i;return ot+i}c(at,"randomColor");function st(i,t,e){return((1<<24)+(i<<16)+(t<<8)+e).toString(16).slice(1)}c(st,"rgbToHex");function ht(i,t,e,n=1){return`rgba(${i},${t},${e},${n})`}c(ht,"rgba");function X(i){return i*Math.PI/180}c(X,"angleToRadian");function kt(i){return i*180/Math.PI}c(kt,"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}}c(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}}}c(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}}}c(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,d=1/0,h=-1/0,l=-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),d=Math.min(d,B.y),h=Math.max(h,B.x),l=Math.max(l,B.y)}return{x:s,y:d,width:h-s,height:l-d}}c(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}};c(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 P=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=at();if(e&&!P.has(e)){this.key=e,P.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(){P.delete(this.key),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)}};c(Q,"Shape");var Y=Q;function O(i){return typeof i.resizable=="object"&&!!i.resizable.aspectRatio}c(O,"isLockAspectRatioResize");import{animationFrames as wt,filter as W,Subject as gt,takeUntil as j}from"rxjs";var Z=class Z extends Y{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,d=e.y-this.target.y,h=this.getAnchorLocalPoint(e.width,e.height),l={x:s+h.x,y:d+h.y},o=U(l,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:d,rotation:h,strokeWidth:l}=this;e.save(),h&&(e.translate(n,s),e.rotate(X(h))),e.beginPath(),e.arc(h?0:n,h?0:s,this.getRadius(),0,Math.PI*2,!1),e.fill(),d&&(e.lineWidth=(l!=null?l: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 d;let e=this.innerBox(),n=(d=this.strokeWidth)!=null?d: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}};c(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:d,canvasEvents:h,clientEvents:l}=t;this.context=e.getContext("2d"),this.shadowContext=n.getContext("2d",{willReadFrequently:!0}),this.draggableContext=s.getContext("2d"),this.draftContext=d.getContext("2d");for(let x of this.anchors)x.stage=this;this.resize();let o,a,r,B,I=!1;h.pipe(W(x=>x.type==="pointerdown"),j(this.destroyed$)).subscribe(x=>{if(x.button!==void 0&&x.button!==0)return;I=!0,o=x.offsetX,a=x.offsetY;let $=L(x.offsetX),N=L(x.offsetY),D=this.getShadowColor($,N),S=P.get(D);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()}),l.pipe(W(x=>x.type==="pointermove"),W(()=>I),j(this.destroyed$)).subscribe(x=>{let $=x.offsetX,N=x.offsetY,D=($-o)/this.scale,S=(N-a)/this.scale;if(this.activatedShape instanceof v){this.snapLines=null;let C=this.activatedShape,g=C.target,{rotation:H}=g,E=ct(D,S,H),p=E.x,R=E.y,k=0,w=0,f=r.width,u=r.height;switch(C.direction){case 7:k=p,w=R,u=r.height-R,f=r.width-p;break;case 0:w=R,u=r.height-R,O(g)&&(f=u*g.resizable.aspectRatio);break;case 4:w=R,u=r.height-R,f=r.width+p;break;case 1:f=r.width+p,O(g)&&(u=f/g.resizable.aspectRatio);break;case 5:f=r.width+p,u=r.height+R;break;case 2:u=r.height+R,O(g)&&(f=u*g.resizable.aspectRatio);break;case 6:u=r.height+R,k=p,f=r.width-p;break;case 3:k=p,f=r.width-p,O(g)&&(u=f/g.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)),f=Math.max(M,f),u=Math.max(b,u),k=Math.round(k),w=Math.round(w),f=Math.round(f),u=Math.round(u);let m=dt(k,w,H);g.x=Math.round(B.x+m.x),g.y=Math.round(B.y+m.y),g.setWidth?g.setWidth(Math.max(1,f)):g.width=Math.max(1,f),g.setHeight?g.setHeight(Math.max(1,u)):g.height=Math.max(1,u)}else if(this.activatedShape){let C=Math.round(B.x+D),g=Math.round(B.y+S),H=1/0,E=1/0;this.activatedShape.x=C,this.activatedShape.y=g;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,f=0,u,M;for(let b of R)switch(b.placement){case 0:{let m=p.y+f,F=p.y+p.height/2+f,G=p.y+p.height+f,q=[b.position-m,b.position-F,b.position-G];for(let V of q){let A=Math.abs(V);A<=k&&A<E&&(f=V,E=A,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 V of q){let A=Math.abs(V);A<=k&&A<H&&(w=V,H=A,u=b.position)}break}}C=Math.round(C+w),g=Math.round(g+f),this.snapLines=u!==void 0||M!==void 0?{x:u,y:M}:null,this.activatedShape.x=C,this.activatedShape.y=g}}),l.pipe(W(x=>x.type==="pointerup"||x.type==="pointercancel"),j(this.destroyed$)).subscribe(()=>{I=!1,this.snapLines=null,this.render()}),wt().pipe(W(()=>I&&!!this.activatedShape),j(this.destroyed$)).subscribe(()=>{this.drawDraggable()})}resize(t){Object.assign(this.config,t);let{sceneCanvas:e,shadowCanvas:n,draggableCanvas:s,draftCanvas:d,width:h,height:l,dpr:o}=this.config;for(let a of[e,n,s,d]){let r=a.getContext("2d");a.style.width=z(h),a.style.height=z(l),a.width=L(h),a.height=L(l),r.scale(o,o)}}zoom(t){let{sceneCanvas:e,shadowCanvas:n,draggableCanvas:s,draftCanvas:d,dpr:h,width:l,height:o}=this.config;for(let a of[e,n,s,d]){let r=a.getContext("2d");a.style.width=z(l*t),a.style.height=z(o*t),a.width=L(l*t),a.height=L(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){let s=this.shapes.indexOf(n);s!==-1&&(n.destroy(),this.shapes.splice(s,1),e===n&&this.setActivatedShape(null),this.emit({type:"remove",target:n}))}for(let n=0;n<this.shapes.length;n++)this.shapes[n].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:d}=t,h=t.boundingBox();if(e.save(),d&&(e.translate(n,s),e.rotate(X(d))),e.fillStyle=T.White,e.strokeStyle=T.Primary,e.lineWidth=2/this.scale,e.strokeRect(d?h.x-n:h.x,d?h.y-s:h.y,h.width,h.height),e.restore(),!t.resizable)return;let l=[];typeof t.resizable=="object"&&(t.resizable.aspectRatio?l=[0,1,2,3]:t.resizable.directions&&(l=t.resizable.directions));for(let a of this.anchors)l.length&&!l.includes(a.direction)||(e.fillStyle=(o=a.fill)!=null?o:T.Transparent,e.strokeStyle=a.stroke,a.rotation=d,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(st(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(W(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)})}};c(_,"Stage");var ft=_;export{T as Color,lt as Placement,y as ReferenceLine,mt as ResizeDirection,Y as Shape,ft as Stage,X as angleToRadian,Ct as dotToPixel,O as isLockAspectRatioResize,dt as localDeltaToWorldRightAngle,Rt as millimeterToPixel,St as pixelToDot,Bt as pixelToMillimeter,kt as radianToAngle,at as randomColor,st as rgbToHex,ht as rgba,J as rotateBoxRightAngle,U as rotatePointRightAngle,L as withDpr,rt as withHash,z as withPixel,ct as worldDeltaToLocalRightAngle};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sunspots/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
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": "8c984a1f9793fade14eb872f87a063ae8bfbded1"
|
|
32
32
|
}
|