| import { PathStyleProps } from '../Path'; | 
|   | 
| /** | 
|  * Sub-pixel optimize for canvas rendering, prevent from blur | 
|  * when rendering a thin vertical/horizontal line. | 
|  */ | 
|   | 
| const round = Math.round; | 
|   | 
| type LineShape = { | 
|     x1: number | 
|     y1: number | 
|     x2: number | 
|     y2: number | 
| } | 
|   | 
| type RectShape = { | 
|     x: number | 
|     y: number | 
|     width: number | 
|     height: number | 
|     r?: number | number[] | 
| } | 
| /** | 
|  * Sub pixel optimize line for canvas | 
|  * | 
|  * @param outputShape The modification will be performed on `outputShape`. | 
|  *                 `outputShape` and `inputShape` can be the same object. | 
|  *                 `outputShape` object can be used repeatly, because all of | 
|  *                 the `x1`, `x2`, `y1`, `y2` will be assigned in this method. | 
|  */ | 
| export function subPixelOptimizeLine( | 
|     outputShape: Partial<LineShape>, | 
|     inputShape: LineShape, | 
|     style: Pick<PathStyleProps, 'lineWidth'>   // DO not optimize when lineWidth is 0 | 
| ): LineShape { | 
|     if (!inputShape) { | 
|         return; | 
|     } | 
|   | 
|     const x1 = inputShape.x1; | 
|     const x2 = inputShape.x2; | 
|     const y1 = inputShape.y1; | 
|     const y2 = inputShape.y2; | 
|   | 
|     outputShape.x1 = x1; | 
|     outputShape.x2 = x2; | 
|     outputShape.y1 = y1; | 
|     outputShape.y2 = y2; | 
|   | 
|     const lineWidth = style && style.lineWidth; | 
|     if (!lineWidth) { | 
|         return outputShape as LineShape; | 
|     } | 
|   | 
|     if (round(x1 * 2) === round(x2 * 2)) { | 
|         outputShape.x1 = outputShape.x2 = subPixelOptimize(x1, lineWidth, true); | 
|     } | 
|     if (round(y1 * 2) === round(y2 * 2)) { | 
|         outputShape.y1 = outputShape.y2 = subPixelOptimize(y1, lineWidth, true); | 
|     } | 
|   | 
|     return outputShape as LineShape; | 
| } | 
|   | 
| /** | 
|  * Sub pixel optimize rect for canvas | 
|  * | 
|  * @param outputShape The modification will be performed on `outputShape`. | 
|  *                 `outputShape` and `inputShape` can be the same object. | 
|  *                 `outputShape` object can be used repeatly, because all of | 
|  *                 the `x`, `y`, `width`, `height` will be assigned in this method. | 
|  */ | 
| export function subPixelOptimizeRect( | 
|     outputShape: Partial<RectShape>, | 
|     inputShape: RectShape, | 
|     style: Pick<PathStyleProps, 'lineWidth'>   // DO not optimize when lineWidth is 0 | 
| ): RectShape { | 
|     if (!inputShape) { | 
|         return; | 
|     } | 
|   | 
|     const originX = inputShape.x; | 
|     const originY = inputShape.y; | 
|     const originWidth = inputShape.width; | 
|     const originHeight = inputShape.height; | 
|   | 
|     outputShape.x = originX; | 
|     outputShape.y = originY; | 
|     outputShape.width = originWidth; | 
|     outputShape.height = originHeight; | 
|   | 
|     const lineWidth = style && style.lineWidth; | 
|     if (!lineWidth) { | 
|         return outputShape as RectShape; | 
|     } | 
|   | 
|     outputShape.x = subPixelOptimize(originX, lineWidth, true); | 
|     outputShape.y = subPixelOptimize(originY, lineWidth, true); | 
|     outputShape.width = Math.max( | 
|         subPixelOptimize(originX + originWidth, lineWidth, false) - outputShape.x, | 
|         originWidth === 0 ? 0 : 1 | 
|     ); | 
|     outputShape.height = Math.max( | 
|         subPixelOptimize(originY + originHeight, lineWidth, false) - outputShape.y, | 
|         originHeight === 0 ? 0 : 1 | 
|     ); | 
|   | 
|     return outputShape as RectShape; | 
| } | 
|   | 
| /** | 
|  * Sub pixel optimize for canvas | 
|  * | 
|  * @param position Coordinate, such as x, y | 
|  * @param lineWidth If `null`/`undefined`/`0`, do not optimize. | 
|  * @param positiveOrNegative Default false (negative). | 
|  * @return Optimized position. | 
|  */ | 
| export function subPixelOptimize( | 
|     position: number, | 
|     lineWidth?: number, | 
|     positiveOrNegative?: boolean | 
| ) { | 
|     if (!lineWidth) { | 
|         return position; | 
|     } | 
|     // Assure that (position + lineWidth / 2) is near integer edge, | 
|     // otherwise line will be fuzzy in canvas. | 
|     const doubledPosition = round(position * 2); | 
|     return (doubledPosition + round(lineWidth)) % 2 === 0 | 
|         ? doubledPosition / 2 | 
|         : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2; | 
| } |