import * as d3 from 'd3'; import { isCircleStyle, ShapeStyle } from '../../styles/ShapeStyle'; import { Node } from '../../types/Node'; import { Point } from '../../types/Point'; import { ShapeRenderer } from './ShapeRenderer'; const TWOPI = 2 * Math.PI; const PI6 = Math.PI / 6; class CircleRenderer extends ShapeRenderer { static defaultRadius = 60; protected _radius: number; constructor (style?: ShapeStyle) { super(style); this._radius = CircleRenderer.defaultRadius; if (style && isCircleStyle(style)) { if (style.radius) this._radius = style.radius; } } containsPoint (node: Node, x: number, y: number, scale?: number): boolean { scale = scale || 1; const dx = x - node.x; const dy = y - node.y; const d2 = dx * dx + dy * dy; const r = this._radius / scale; return d2 < r * r; } intersect (angle: number): Point { return { x: this._radius * Math.cos(angle), y: this._radius * Math.sin(angle) } } radius (): number; radius (radius: number): CircleRenderer; radius (radius?: number): number | CircleRenderer { return arguments.length ? (this._radius = +radius!, this) : this._radius; } render(context: CanvasRenderingContext2D, x: d3.ScaleLinear, y: d3.ScaleLinear): void { if (!this._nodes.length) return; context.save(); context.beginPath(); this._nodes.forEach(point => { const px = x(point.x); const py = y(point.y); context.moveTo(px + this._radius, py); context.arc(px, py, this._radius, 0, TWOPI); }); this._doStrokeAndFill(context); context.restore(); } selfLoopPoints (node: Node): Point[] { const nx = node.x; const ny = node.y; const d = 3; return [{ x: nx, y: ny, dx: this._radius * Math.cos(-PI6), dy: this._radius * Math.sin(-PI6) }, { x: nx, y: ny, dx: d * this._radius * Math.cos(-PI6), dy: d * this._radius * Math.sin(-PI6) }, { x: nx, y: ny, dx: d * this._radius * Math.cos(PI6), dy: d * this._radius * Math.sin(PI6) }, { x: nx, y: ny, dx: this._radius * Math.cos(PI6), dy: this._radius * Math.sin(PI6) }]; } } export { CircleRenderer }