Skip to content

Commit

Permalink
Potential Safari workaround for incorrect Quadratic paths - using de …
Browse files Browse the repository at this point in the history
…Casteljau subdivision (one level) on quadratic bezier curves in Safari, see phetsims/graphing-quadratics#206
  • Loading branch information
jonathanolson committed Apr 3, 2024
1 parent c5c8e4a commit aca16ca
Showing 1 changed file with 48 additions and 0 deletions.
48 changes: 48 additions & 0 deletions js/Shape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,54 @@ class Shape implements CanApplyParsedSVG {
return string;
}

/**
* Returns something like "M150 0 L75 200 L225 200 Z" for a triangle (to be used with a SVG path element's 'd'
* attribute)
*
* Patched to work around https://github.com/phetsims/graphing-quadratics/issues/206, by splitting Quadratic Bezier
* segments into half with the de Casteljau algorithm.
*/
public getSVGPathWithSafariWorkaround(): string {
let string = '';
const len = this.subpaths.length;
for ( let i = 0; i < len; i++ ) {
const subpath = this.subpaths[ i ];
if ( subpath.isDrawable() ) {
// since the commands after this are relative to the previous 'point', we need to specify a move to the initial point
const startPoint = subpath.segments[ 0 ].start;

string += `M ${svgNumber( startPoint.x )} ${svgNumber( startPoint.y )} `;

for ( let k = 0; k < subpath.segments.length; k++ ) {
const segment = subpath.segments[ k ];
if ( segment instanceof Quadratic ) {
const start = segment.start;
const control = segment.control;
const end = segment.end;

const startMidX = ( start.x + control.x ) / 2;
const startMidY = ( start.y + control.y ) / 2;
const endMidX = ( control.x + end.x ) / 2;
const endMidY = ( control.y + end.y ) / 2;
const midX = ( startMidX + endMidX ) / 2;
const midY = ( startMidY + endMidY ) / 2;

string += `Q ${svgNumber( startMidX )} ${svgNumber( startMidY )} ${svgNumber( midX )} ${svgNumber( midY )} `;
string += `Q ${svgNumber( endMidX )} ${svgNumber( endMidY )} ${svgNumber( end.x )} ${svgNumber( end.y )} `;
}
else {
string += `${subpath.segments[ k ].getSVGPathFragment()} `;
}
}

if ( subpath.isClosed() ) {
string += 'Z ';
}
}
}
return string;
}

/**
* Returns a new Shape that is transformed by the associated matrix
*/
Expand Down

0 comments on commit aca16ca

Please sign in to comment.