11import { loopAccess } from "./util" ;
2- import { Point , interpolate } from "./point" ;
32import { xml , XmlElement } from "../../editable" ;
3+ import { Shape } from "../types" ;
4+ import { expandHandle } from "../shape/util" ;
45
56export interface RenderOptions {
67 // Viewport size.
@@ -26,45 +27,15 @@ export interface RenderOptions {
2627
2728// Renders a shape made up of the input points to an editable data structure
2829// which can be rendered to svg.
29- export const renderEditable = ( p : Point [ ] , opt : RenderOptions ) : XmlElement => {
30- const points = p . map ( ( point ) => interpolate ( point , opt . height ) ) ;
31-
32- // Compute guides from input point data.
33- const handles : { x1 : number ; y1 : number ; x2 : number ; y2 : number } [ ] = [ ] ;
30+ export const renderEditable = ( points : Shape , opt : RenderOptions ) : XmlElement => {
31+ // Render path data attribute from points and handles.
32+ let path = `M${ points [ 0 ] . x } ,${ points [ 0 ] . y } ` ;
3433 for ( let i = 0 ; i < points . length ; i ++ ) {
35- const { x, y, handles : hands } = loopAccess ( points ) ( i ) ;
36-
34+ const curr = loopAccess ( points ) ( i ) ;
3735 const next = loopAccess ( points ) ( i + 1 ) ;
38- const nextHandles = next . handles ;
39-
40- if ( hands === undefined ) {
41- handles . push ( { x1 : x , y1 : y , x2 : next . x , y2 : next . y } ) ;
42- continue ;
43- }
44-
45- handles . push ( {
46- x1 : x - Math . cos ( hands . angle ) * hands . out ,
47- y1 : y + Math . sin ( hands . angle ) * hands . out ,
48- x2 : next . x + Math . cos ( nextHandles . angle ) * nextHandles . in ,
49- y2 : next . y - Math . sin ( nextHandles . angle ) * nextHandles . in ,
50- } ) ;
51- }
52-
53- // Render path data attribute from points and handles. Must loop more times
54- // than the number of points in order to correctly close the path.
55- let path = "" ;
56- for ( let i = 0 ; i <= points . length ; i ++ ) {
57- const point = loopAccess ( points ) ( i ) ;
58- const hands = loopAccess ( handles ) ( i - 1 ) ;
59-
60- // Start at the first point's coordinates.
61- if ( i === 0 ) {
62- path += `M${ point . x } ,${ point . y } ` ;
63- continue ;
64- }
65-
66- // Add cubic bezier coordinates using the computed handle positions.
67- path += `C${ hands . x1 } ,${ hands . y1 } ,${ hands . x2 } ,${ hands . y2 } ,${ point . x } ,${ point . y } ` ;
36+ const currControl = expandHandle ( curr , curr . handleOut ) ;
37+ const nextControl = expandHandle ( next , next . handleIn ) ;
38+ path += `C${ currControl . x } ,${ currControl . y } ,${ nextControl . x } ,${ nextControl . y } ,${ next . x } ,${ next . y } ` ;
6839 }
6940
7041 const stroke = opt . stroke || ( opt . guides ? "black" : "none" ) ;
@@ -109,49 +80,50 @@ export const renderEditable = (p: Point[], opt: RenderOptions): XmlElement => {
10980
11081 // Points and handles.
11182 for ( let i = 0 ; i < points . length ; i ++ ) {
112- const { x, y} = loopAccess ( points ) ( i ) ;
113- const hands = loopAccess ( handles ) ( i ) ;
114- const nextPoint = loopAccess ( points ) ( i + 1 ) ;
115-
116- const xmlIncomingHandleLine = xml ( "line" ) ;
117- xmlIncomingHandleLine . attributes . x1 = x ;
118- xmlIncomingHandleLine . attributes . y1 = y ;
119- xmlIncomingHandleLine . attributes . x2 = hands . x1 ;
120- xmlIncomingHandleLine . attributes . y2 = hands . y1 ;
121- xmlIncomingHandleLine . attributes [ "stroke-width" ] = size ;
122- xmlIncomingHandleLine . attributes . stroke = color ;
83+ const curr = loopAccess ( points ) ( i ) ;
84+ const next = loopAccess ( points ) ( i + 1 ) ;
85+ const currControl = expandHandle ( curr , curr . handleOut ) ;
86+ const nextControl = expandHandle ( next , next . handleIn ) ;
12387
12488 const xmlOutgoingHandleLine = xml ( "line" ) ;
125- xmlOutgoingHandleLine . attributes . x1 = nextPoint . x ;
126- xmlOutgoingHandleLine . attributes . y1 = nextPoint . y ;
127- xmlOutgoingHandleLine . attributes . x2 = hands . x2 ;
128- xmlOutgoingHandleLine . attributes . y2 = hands . y2 ;
89+ xmlOutgoingHandleLine . attributes . x1 = curr . x ;
90+ xmlOutgoingHandleLine . attributes . y1 = curr . y ;
91+ xmlOutgoingHandleLine . attributes . x2 = currControl . x ;
92+ xmlOutgoingHandleLine . attributes . y2 = currControl . y ;
12993 xmlOutgoingHandleLine . attributes [ "stroke-width" ] = size ;
13094 xmlOutgoingHandleLine . attributes . stroke = color ;
131- xmlOutgoingHandleLine . attributes [ "stroke-dasharray" ] = 2 * size ;
13295
133- const xmlIncomingHandleCircle = xml ( "circle" ) ;
134- xmlIncomingHandleCircle . attributes . cx = hands . x1 ;
135- xmlIncomingHandleCircle . attributes . cy = hands . y1 ;
136- xmlIncomingHandleCircle . attributes . r = size ;
137- xmlIncomingHandleCircle . attributes . fill = color ;
96+ const xmlIncomingHandleLine = xml ( "line" ) ;
97+ xmlIncomingHandleLine . attributes . x1 = next . x ;
98+ xmlIncomingHandleLine . attributes . y1 = next . y ;
99+ xmlIncomingHandleLine . attributes . x2 = nextControl . x ;
100+ xmlIncomingHandleLine . attributes . y2 = nextControl . y ;
101+ xmlIncomingHandleLine . attributes [ "stroke-width" ] = size ;
102+ xmlIncomingHandleLine . attributes . stroke = color ;
103+ xmlIncomingHandleLine . attributes [ "stroke-dasharray" ] = 2 * size ;
138104
139105 const xmlOutgoingHandleCircle = xml ( "circle" ) ;
140- xmlOutgoingHandleCircle . attributes . cx = hands . x2 ;
141- xmlOutgoingHandleCircle . attributes . cy = hands . y2 ;
106+ xmlOutgoingHandleCircle . attributes . cx = currControl . x ;
107+ xmlOutgoingHandleCircle . attributes . cy = currControl . y ;
142108 xmlOutgoingHandleCircle . attributes . r = size ;
143109 xmlOutgoingHandleCircle . attributes . fill = color ;
144110
111+ const xmlIncomingHandleCircle = xml ( "circle" ) ;
112+ xmlIncomingHandleCircle . attributes . cx = nextControl . x ;
113+ xmlIncomingHandleCircle . attributes . cy = nextControl . y ;
114+ xmlIncomingHandleCircle . attributes . r = size ;
115+ xmlIncomingHandleCircle . attributes . fill = color ;
116+
145117 const xmlPointCircle = xml ( "circle" ) ;
146- xmlPointCircle . attributes . cx = x ;
147- xmlPointCircle . attributes . cy = y ;
118+ xmlPointCircle . attributes . cx = curr . x ;
119+ xmlPointCircle . attributes . cy = curr . y ;
148120 xmlPointCircle . attributes . r = 2 * size ;
149121 xmlPointCircle . attributes . fill = color ;
150122
151- xmlContentGroup . children . push ( xmlIncomingHandleLine ) ;
152123 xmlContentGroup . children . push ( xmlOutgoingHandleLine ) ;
153- xmlContentGroup . children . push ( xmlIncomingHandleCircle ) ;
124+ xmlContentGroup . children . push ( xmlIncomingHandleLine ) ;
154125 xmlContentGroup . children . push ( xmlOutgoingHandleCircle ) ;
126+ xmlContentGroup . children . push ( xmlIncomingHandleCircle ) ;
155127 xmlContentGroup . children . push ( xmlPointCircle ) ;
156128 }
157129 }
0 commit comments