diff --git a/src/ExcalidrawAutomate.ts b/src/ExcalidrawAutomate.ts index 4ab5c5b..c986110 100644 --- a/src/ExcalidrawAutomate.ts +++ b/src/ExcalidrawAutomate.ts @@ -59,7 +59,8 @@ export interface ExcalidrawAutomate extends Window { addRect(topX:number, topY:number, width:number, height:number):string; addDiamond(topX:number, topY:number, width:number, height:number):string; addEllipse(topX:number, topY:number, width:number, height:number):string; - addText(topX:number, topY:number, text:string, formatting?:{width?:number, height?:number,textAlign?: string, verticalAlign?:string, box?: boolean, boxPadding?: number},id?:string):string; + addBlob(topX:number, topY:number, width:number, height:number):string; + addText(topX:number, topY:number, text:string, formatting?:{wrapAt?:number, width?:number, height?:number,textAlign?: string, verticalAlign?:string, box?: boolean, boxPadding?: number},id?:string):string; addLine(points: [[x:number,y:number]]):string; addArrow(points: [[x:number,y:number]],formatting?:{startArrowHead?:string,endArrowHead?:string,startObjectId?:string,endObjectId?:string}):string ; connectObjects(objectA: string, connectionA: ConnectionPoint, objectB: string, connectionB: ConnectionPoint, formatting?:{numberOfPoints?: number,startArrowHead?:string,endArrowHead?:string, padding?: number}):void; @@ -83,7 +84,6 @@ declare let window: ExcalidrawAutomate; export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) { window.ExcalidrawAutomate = { plugin: plugin, - //elementIds: [], elementsDict: {}, style: { strokeColor: "#000000", @@ -274,28 +274,99 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) { }, addRect(topX:number, topY:number, width:number, height:number):string { const id = nanoid(); - //this.elementIds.push(id); this.elementsDict[id] = boxedElement(id,"rectangle",topX,topY,width,height); return id; }, addDiamond(topX:number, topY:number, width:number, height:number):string { const id = nanoid(); - //this.elementIds.push(id); this.elementsDict[id] = boxedElement(id,"diamond",topX,topY,width,height); return id; }, addEllipse(topX:number, topY:number, width:number, height:number):string { const id = nanoid(); - //this.elementIds.push(id); this.elementsDict[id] = boxedElement(id,"ellipse",topX,topY,width,height); return id; - }, - addText(topX:number, topY:number, text:string, formatting?:{width?:number, height?:number,textAlign?: string, verticalAlign?:string, box?: boolean, boxPadding?: number},id?:string):string { - if(!id) id = nanoid(); + }, + addBlob(topX:number, topY:number, width:number, height:number):string { + const b = height*0.5; //minor axis of the ellipsis + const a = width*0.5; //major axis of the ellipsis + const sx = a/9; + const sy = b*0.8; + const step = 6; + let p:any = []; + const pushPoint = (i:number,dir:number) => { + const x = i + Math.random()*sx-sx/2; + p.push([x+Math.random()*sx-sx/2+(i%2)*sx/6+topX,dir*Math.sqrt(b*b*(1-(x*x)/(a*a)))+Math.random()*sy-sy/2+(i%2)*sy/6+topY]); + } + let i:number; + for (i=-a+sx/2;i<=a-sx/2;i+=a/step) { + pushPoint(i,1); + } + for(i=a-sx/2;i>=-a+sx/2;i-=a/step) { + pushPoint(i,-1); + } + p.push(p[0]); + const id=this.addLine(p); + const scale = (element:ExcalidrawElement):ExcalidrawElement => { + if(!(element.type=="line" || element.type=="arrow")) return null; + const scaleX = width/element.width; + const scaleY = height/element.height; + let i; + for(i=0;i { + const [x,y] = p; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + }); + return[minX,minY,maxX,maxY]; +} + +export function estimateElementBounds (element:ExcalidrawElement):[number,number,number,number] { + if(element.type=="line" || element.type=="arrow") { + const [minX,minY,maxX,maxY] = estimateLineBound(element.points); + return [minX+element.x,minY+element.y,maxX+element.x,maxY+element.y]; + } + return[element.x,element.y,element.x+element.width,element.y+element.height]; +} + +export function estimateBounds (elements:ExcalidrawElement[]):[number,number,number,number] { + if(!elements.length) return [0,0,0,0]; + let minX = Infinity; + let maxX = -Infinity; + let minY = Infinity; + let maxY = -Infinity; + + elements.forEach((element)=>{ + const [x1,y1,x2,y2] = estimateElementBounds(element); + minX = Math.min(minX, x1); + minY = Math.min(minY, y1); + maxX = Math.max(maxX, x2); + maxY = Math.max(maxY, y2); + }); + return [minX,minY,maxX,maxY]; +} + +export function repositionElementsToCursor (elements:ExcalidrawElement[],newPosition:{x:number, y:number},center:boolean=false):ExcalidrawElement[] { + const [x1,y1,x2,y2] = estimateBounds(elements); + let [offsetX,offsetY] = [0,0]; + if (center) { + [offsetX,offsetY] = [newPosition.x-(x1+x2)/2,newPosition.y-(y1+y2)/2]; + } else { + [offsetX,offsetY] = [newPosition.x-x1,newPosition.y-y1]; + } + + elements.forEach((element:any)=>{ //using any so I can write read-only propery x & y + element.x=element.x+offsetX; + element.y=element.y+offsetY; + }); + return elements; +} + function errorMessage(message: string, source: string) { switch(message) { case "targetView not set": diff --git a/src/ExcalidrawView.ts b/src/ExcalidrawView.ts index bf1b835..541257e 100644 --- a/src/ExcalidrawView.ts +++ b/src/ExcalidrawView.ts @@ -31,7 +31,7 @@ import { JSON_parse } from './constants'; import ExcalidrawPlugin from './main'; -import {ExcalidrawAutomate} from './ExcalidrawAutomate'; +import {estimateBounds, ExcalidrawAutomate, repositionElementsToCursor} from './ExcalidrawAutomate'; import { t } from "./lang/helpers"; import { ExcalidrawData, REG_LINKINDEX_HYPERLINK, REGEX_LINK } from "./ExcalidrawData"; import { checkAndCreateFolder, download, getNewUniqueFilepath, splitFolderAndFilename, viewportCoordsToSceneCoords } from "./Utils"; @@ -604,39 +604,8 @@ export default class ExcalidrawView extends TextFileView { } this.addElements = async (newElements:ExcalidrawElement[],repositionToCursor:boolean = false, save:boolean=false):Promise => { - if(!excalidrawRef?.current) return false; - - const estimateElementBounds = (element:ExcalidrawElement):[number,number,number,number] => { - return[element.x,element.y,element.x+element.width,element.y+element.height]; - } - - const estimateBounds = (elements:ExcalidrawElement[]):[number,number,number,number] => { - if(!elements.length) return [0,0,0,0]; - let minX = Infinity; - let maxX = -Infinity; - let minY = Infinity; - let maxY = -Infinity; - - elements.forEach((element)=>{ - const [x1,y1,x2,y2] = estimateElementBounds(element); - minX = Math.min(minX, x1); - minY = Math.min(minY, y1); - maxX = Math.max(maxX, x2); - maxY = Math.max(maxY, y2); - }); - return [minX,minY,maxX,maxY]; - } - - const repositionElementsToCursor = (elements:ExcalidrawElement[]):ExcalidrawElement[] => { - const [x1,y1,x2,y2] = estimateBounds(elements); - const [offsetX,offsetY] = [currentPosition.x-(x1+x2)/2,currentPosition.y-(y1+y2)/2] - elements.forEach((element:any)=>{ //using any so I can write read-only propery x & y - element.x=element.x+offsetX; - element.y=element.y+offsetY; - }); - return elements; - } - + if(!excalidrawRef?.current) return false; + const textElements = newElements.filter((el)=>el.type=="text"); for(let i=0;i