@@ -47,18 +47,19 @@ export interface RenderOptions {
4747
4848 // Option to render guides (points, handles and viewport).
4949 guides ?: boolean ;
50+ boundingBox ?: boolean ;
5051}
5152
5253// Safe array access at any index using a modulo operation that will always be positive.
5354const loopAccess = < T > ( arr : T [ ] ) => ( i : number ) : T => {
54- return arr [ ( ( i % arr . length ) + arr . length ) % arr . length ] ;
55+ return arr [ ( ( i % arr . length ) + arr . length ) % arr . length ] ;
5556} ;
5657
5758// Translates a point's [x,y] cartesian coordinates into values relative to the viewport.
5859// Translates the angle from degrees to radians and moves the start angle a half rotation.
5960const cleanupPoint = ( point : Point , opt : RenderOptions ) : InternalPoint => {
6061 const handles = point . handles || { angle : 0 , out : 0 , in : 0 } ;
61- handles . angle = Math . PI + ( 2 * Math . PI * handles . angle / 360 ) ;
62+ handles . angle = Math . PI + ( 2 * Math . PI * handles . angle ) / 360 ;
6263 return {
6364 x : point . x ,
6465 y : opt . height - point . y ,
@@ -71,11 +72,11 @@ const renderClosed = (p: Point[], opt: RenderOptions): string => {
7172 const points = p . map ( ( point ) => cleanupPoint ( point , opt ) ) ;
7273
7374 // Compute guides from input point data.
74- const handles : { x1 : number , y1 : number , x2 : number , y2 : number } [ ] = [ ] ;
75+ const handles : { x1 : number ; y1 : number ; x2 : number ; y2 : number } [ ] = [ ] ;
7576 for ( let i = 0 ; i < points . length ; i ++ ) {
7677 const { x, y, handles : hands } = loopAccess ( points ) ( i ) ;
7778
78- const next = loopAccess ( points ) ( i + 1 ) ;
79+ const next = loopAccess ( points ) ( i + 1 ) ;
7980 const nextHandles = next . handles ;
8081
8182 if ( hands === undefined ) {
@@ -96,7 +97,7 @@ const renderClosed = (p: Point[], opt: RenderOptions): string => {
9697 let path = "" ;
9798 for ( let i = 0 ; i <= points . length ; i ++ ) {
9899 const point = loopAccess ( points ) ( i ) ;
99- const hands = loopAccess ( handles ) ( i - 1 ) ;
100+ const hands = loopAccess ( handles ) ( i - 1 ) ;
100101
101102 // Start at the first point's coordinates.
102103 if ( i === 0 ) {
@@ -111,31 +112,39 @@ const renderClosed = (p: Point[], opt: RenderOptions): string => {
111112 // Render guides if configured to do so.
112113 let guides = "" ;
113114 if ( opt . guides ) {
115+ const color = opt . stroke || "black" ;
116+ const size = opt . strokeWidth || 1 ;
117+
114118 // Bounding box.
115- guides += `
116- <rect x="0" y="0" width="${ opt . width } " height="${ opt . height } "
117- fill="none" stroke="black" stroke-width="1" stroke-dasharray="2" />` ;
119+ if ( opt . boundingBox ) {
120+ guides += `
121+ <rect x="0" y="0" width="${ opt . width } " height="${ opt . height } " fill="none"
122+ stroke="${ color } " stroke-width="${ 2 * size } " stroke-dasharray="${ 2 * size } " />` ;
123+ }
118124
119125 // Points and handles.
120126 for ( let i = 0 ; i < points . length ; i ++ ) {
121127 const { x, y} = loopAccess ( points ) ( i ) ;
122128 const hands = loopAccess ( handles ) ( i ) ;
123- const nextPoint = loopAccess ( points ) ( i + 1 ) ;
129+ const nextPoint = loopAccess ( points ) ( i + 1 ) ;
124130
125131 guides += `
126132 <line x1="${ x } " y1="${ y } " x2="${ hands . x1 } " y2="${ hands . y1 } "
127- stroke-width="1 " stroke="black " />
133+ stroke-width="${ size } " stroke="${ color } " />
128134 <line x1="${ nextPoint . x } " y1="${ nextPoint . y } " x2="${ hands . x2 } " y2="${ hands . y2 } "
129- stroke-width="1 " stroke="black " stroke-dasharray="2 " />
130- <circle cx="${ hands . x1 } " cy="${ hands . y1 } " r="1 "
131- fill="black " />
132- <circle cx="${ hands . x2 } " cy="${ hands . y2 } " r="1 "
133- fill="black " />
134- <circle cx="${ x } " cy="${ y } " r="2 " fill="black " />` ;
135+ stroke-width="${ size } " stroke="${ color } " stroke-dasharray="${ 2 * size } " />
136+ <circle cx="${ hands . x1 } " cy="${ hands . y1 } " r="${ size } "
137+ fill="${ color } " />
138+ <circle cx="${ hands . x2 } " cy="${ hands . y2 } " r="${ size } "
139+ fill="${ color } " />
140+ <circle cx="${ x } " cy="${ y } " r="${ 2 * size } " fill="${ color } " />` ;
135141 }
136142 }
137143
138- return ( `
144+ const stroke = opt . stroke || ( opt . guides ? "black" : "none" ) ;
145+ const strokeWidth = opt . strokeWidth || ( opt . guides ? 1 : 0 ) ;
146+
147+ return `
139148 <svg
140149 width="${ opt . width } "
141150 height="${ opt . height } "
@@ -144,26 +153,32 @@ const renderClosed = (p: Point[], opt: RenderOptions): string => {
144153 >
145154 <g transform="${ opt . transform || "" } ">
146155 <path
147- stroke="${ opt . stroke || "none" } "
148- stroke-width="${ opt . strokeWidth || 0 } "
156+ stroke="${ stroke } "
157+ stroke-width="${ strokeWidth } "
149158 fill="${ opt . fill || "none" } "
150159 d="${ path } "
151160 />
152161 ${ guides }
153162 </g>
154163 </svg>
155- ` ) . replace ( / \s + / g, " " ) ;
164+ ` . replace ( / \s + / g, " " ) ;
156165} ;
157166
158- console . log ( renderClosed ( [
159- { x : 700 , y : 200 , handles : { angle : - 135 , out : 80 , in : 80 } } ,
160- { x : 300 , y : 200 , handles : { angle : 135 , out : 80 , in : 80 } } ,
161- { x : 300 , y : 600 , handles : { angle : 45 , out : 80 , in : 80 } } ,
162- { x : 700 , y : 600 , handles : { angle : - 45 , out : 80 , in : 80 } } ,
163- ] , {
164- width : 1000 ,
165- height : 800 ,
166- stroke : "blue" ,
167- strokeWidth : 1 ,
168- guides : true ,
169- } ) ) ;
167+ console . log (
168+ renderClosed (
169+ [
170+ { x : 700 , y : 200 , handles : { angle : - 135 , out : 80 , in : 80 } } ,
171+ { x : 300 , y : 200 , handles : { angle : 135 , out : 80 , in : 80 } } ,
172+ { x : 300 , y : 600 , handles : { angle : 45 , out : 80 , in : 80 } } ,
173+ { x : 700 , y : 600 , handles : { angle : - 45 , out : 80 , in : 80 } } ,
174+ ] ,
175+ {
176+ width : 1000 ,
177+ height : 800 ,
178+ fill : "pink" ,
179+ stroke : "red" ,
180+ strokeWidth : 2 ,
181+ guides : true ,
182+ } ,
183+ ) ,
184+ ) ;
0 commit comments