Skip to content

Commit 8b3386e

Browse files
authored
Merge pull request #30 from bertyhell/rounded-line-endings
Add rounded line endings to lines and arcs
2 parents 583b21c + 114c1ac commit 8b3386e

File tree

3 files changed

+35
-6
lines changed

3 files changed

+35
-6
lines changed

src/drawControllers/screenCanvas.drawController.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,18 @@ export class ScreenCanvasDrawController implements DrawController {
238238
this.context.moveTo(screenStartPoint.x, this.canvasSize.y - screenStartPoint.y);
239239
this.context.lineTo(screenEndPoint.x, this.canvasSize.y - screenEndPoint.y);
240240
this.context.stroke();
241+
242+
const lineWidth = this.context.lineWidth;
243+
const style = this.context.strokeStyle as string;
244+
this._drawRoundedEndpoint(screenStartPoint, lineWidth, style);
245+
this._drawRoundedEndpoint(screenEndPoint, lineWidth, style);
246+
}
247+
248+
private _drawRoundedEndpoint(screenPoint: Point, lineWidth: number, style: string): void {
249+
this.context.fillStyle = style;
250+
this.context.beginPath();
251+
this.context.arc(screenPoint.x, this.canvasSize.y - screenPoint.y, lineWidth / 2, 0, 2 * Math.PI);
252+
this.context.fill();
241253
}
242254

243255
/**
@@ -283,6 +295,23 @@ export class ScreenCanvasDrawController implements DrawController {
283295
counterClockWise,
284296
);
285297
this.context.stroke();
298+
299+
const lineWidth = this.context.lineWidth;
300+
const style = this.context.strokeStyle as string;
301+
302+
// Calculate arc endpoints
303+
const startScreenX = screenCenterPoint.x + screenRadius * Math.cos(startAngle);
304+
// Y is inverted in canvas, but also for the arc angles, so we subtract from canvasSize.y and then add sin
305+
const startScreenY = (this.canvasSize.y - screenCenterPoint.y) + screenRadius * Math.sin(startAngle);
306+
const endScreenX = screenCenterPoint.x + screenRadius * Math.cos(endAngle);
307+
const endScreenY = (this.canvasSize.y - screenCenterPoint.y) + screenRadius * Math.sin(endAngle);
308+
309+
// Convert back to Point objects, note that _drawRoundedEndpoint expects y to be from top of canvas
310+
const arcStartPoint = new Point(startScreenX, this.canvasSize.y - startScreenY);
311+
const arcEndPoint = new Point(endScreenX, this.canvasSize.y - endScreenY);
312+
313+
this._drawRoundedEndpoint(arcStartPoint, lineWidth, style);
314+
this._drawRoundedEndpoint(arcEndPoint, lineWidth, style);
286315
}
287316

288317
/**

src/drawControllers/svg.drawController.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ export class SvgDrawController implements DrawController {
159159
public drawLine(startPoint: Point, endPoint: Point): void {
160160
const [canvasStartPoint, canvasEndPoint] = this.worldsToTargets([startPoint, endPoint]);
161161
this.svgStrings.push(
162-
`<line x1="${canvasStartPoint.x}" y1="${canvasStartPoint.y}" x2="${canvasEndPoint.x}" y2="${canvasEndPoint.y}" stroke="${this.lineColor}" stroke-width="${this.lineWidth}" stroke-dasharray="${this.lineDash.join(',')}" />`
162+
`<line x1="${canvasStartPoint.x}" y1="${canvasStartPoint.y}" x2="${canvasEndPoint.x}" y2="${canvasEndPoint.y}" stroke="${this.lineColor}" stroke-width="${this.lineWidth}" stroke-dasharray="${this.lineDash.join(',')}" stroke-linecap="round" />`
163163
);
164164
}
165165

@@ -190,12 +190,12 @@ export class SvgDrawController implements DrawController {
190190
const largeArcFlag = Math.abs(sweep) > Math.PI ? '1' : '0';
191191
const sweepFlag = counterClockwise ? '0' : '1'; // SVG: 0 = CCW, 1 = CW
192192

193-
const attributes = `fill="none" stroke="${this.lineColor}" stroke-width="${this.lineWidth}" stroke-dasharray="${this.lineDash.join(',')}"`;
193+
const attributes = `fill="none" stroke="${this.lineColor}" stroke-width="${this.lineWidth}" stroke-dasharray="${this.lineDash.join(',')}" stroke-linecap="round"`;
194194
let svgPath: string;
195195
if (isLengthEqual(sweep, 2 * Math.PI)) {
196196
svgPath = `<circle cx="${canvasCenterPoint.x}" cy="${canvasCenterPoint.y}" r="${canvasRadius}" ${attributes} />`;
197197
} else {
198-
svgPath = `<path d="M${startPoint.x},${startPoint.y} A${canvasRadius},${canvasRadius} 0 ${largeArcFlag},${sweepFlag} ${endPoint.x},${endPoint.y}" ${attributes} />`;
198+
svgPath = `<path d="M${startPoint.x},${startPoint.y} A${canvasRadius},${canvasRadius} 0 ${largeArcFlag},${sweepFlag} ${endPoint.x},${endPoint.y}" ${attributes} />`;
199199
}
200200

201201
// Push the SVG path data string to the svgStrings array

src/helpers/import-export-handlers/import-entities-from-json.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import {type Entity, EntityName, type JsonEntity} from '../../entities/Entity';
55
import {LineEntity, type LineJsonData} from '../../entities/LineEntity';
66
import {PointEntity, type PointJsonData} from '../../entities/PointEntity';
77
import {RectangleEntity, type RectangleJsonData} from '../../entities/RectangleEntity';
8-
import {setActiveLayerId, setEntities, setLayers} from '../../state.ts';
9-
import {getNewLayer} from '../get-new-layer.ts';
10-
import type {JsonDrawingFileDeserialized, JsonDrawingFileSerialized,} from './export-entities-to-json.ts';
8+
import {setActiveLayerId, setEntities, setLayers} from '../../state';
9+
import type {JsonDrawingFileDeserialized, JsonDrawingFileSerialized} from './export-entities-to-json';
10+
import {getNewLayer} from "../get-new-layer.ts";
1111

1212
/**
1313
* Open a file selection dialog to select *.json files

0 commit comments

Comments
 (0)