mirror of
https://github.com/fluxscape/fluxscape.git
synced 2026-01-11 23:02:55 +01:00
Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com> Co-Authored-By: Johan <4934465+joolsus@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
131 lines
3.2 KiB
TypeScript
131 lines
3.2 KiB
TypeScript
import React from 'react';
|
|
|
|
import Layout from '../../../layout';
|
|
import PointerListeners from '../../../pointerlisteners';
|
|
import { Noodl } from '../../../types';
|
|
|
|
export interface CircleProps extends Noodl.ReactProps {
|
|
size: number;
|
|
startAngle: number;
|
|
endAngle: number;
|
|
|
|
fillEnabled: boolean;
|
|
fillColor: Noodl.Color;
|
|
|
|
strokeEnabled: boolean;
|
|
strokeColor: Noodl.Color;
|
|
strokeWidth: number;
|
|
strokeLineCap: 'butt' | 'round';
|
|
|
|
dom;
|
|
}
|
|
|
|
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
|
|
const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0;
|
|
|
|
return {
|
|
x: centerX + radius * Math.cos(angleInRadians),
|
|
y: centerY + radius * Math.sin(angleInRadians)
|
|
};
|
|
}
|
|
|
|
function filledArc(x, y, radius, startAngle, endAngle) {
|
|
if (endAngle % 360 === startAngle % 360) {
|
|
endAngle -= 0.0001;
|
|
}
|
|
|
|
const start = polarToCartesian(x, y, radius, endAngle);
|
|
const end = polarToCartesian(x, y, radius, startAngle);
|
|
|
|
const arcSweep = endAngle - startAngle <= 180 ? '0' : '1';
|
|
|
|
return [
|
|
'M',
|
|
start.x,
|
|
start.y,
|
|
'A',
|
|
radius,
|
|
radius,
|
|
0,
|
|
arcSweep,
|
|
0,
|
|
end.x,
|
|
end.y,
|
|
'L',
|
|
x,
|
|
y,
|
|
'L',
|
|
start.x,
|
|
start.y
|
|
].join(' ');
|
|
}
|
|
|
|
function arc(x, y, radius, startAngle, endAngle) {
|
|
if (endAngle % 360 === startAngle % 360) {
|
|
endAngle -= 0.0001;
|
|
}
|
|
|
|
const start = polarToCartesian(x, y, radius, endAngle);
|
|
const end = polarToCartesian(x, y, radius, startAngle);
|
|
|
|
const arcSweep = endAngle - startAngle <= 180 ? '0' : '1';
|
|
|
|
return ['M', start.x, start.y, 'A', radius, radius, 0, arcSweep, 0, end.x, end.y].join(' ');
|
|
}
|
|
|
|
export class Circle extends React.Component<CircleProps> {
|
|
constructor(props: CircleProps) {
|
|
super(props);
|
|
}
|
|
|
|
render() {
|
|
//SVG can only do strokes centered on a path, and we want to render it inside.
|
|
//We'll do it manually by adding another path on top of the filled circle
|
|
|
|
let fill;
|
|
let stroke;
|
|
|
|
const r = this.props.size / 2;
|
|
const { startAngle, endAngle } = this.props;
|
|
|
|
if (this.props.fillEnabled) {
|
|
const r = this.props.size / 2;
|
|
fill = <path d={filledArc(r, r, r, startAngle, endAngle)} fill={this.props.fillColor} />;
|
|
}
|
|
|
|
if (this.props.strokeEnabled) {
|
|
const { strokeColor, strokeWidth, strokeLineCap } = this.props;
|
|
const strokeRadius = r - this.props.strokeWidth / 2;
|
|
const path = arc(r, r, strokeRadius, startAngle, endAngle);
|
|
stroke = (
|
|
<path
|
|
d={path}
|
|
stroke={strokeColor}
|
|
strokeWidth={strokeWidth}
|
|
fill="transparent"
|
|
strokeLinecap={strokeLineCap}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const style = { ...this.props.style };
|
|
Layout.size(style, this.props);
|
|
Layout.align(style, this.props);
|
|
|
|
if (style.opacity === 0) {
|
|
style.pointerEvents = 'none';
|
|
}
|
|
|
|
//the SVG element lack some properties like offsetLeft, offsetTop that the drag node depends on.
|
|
//Let's wrap it in a div to make it work properly
|
|
return (
|
|
<div className={this.props.className} {...this.props.dom} {...PointerListeners(this.props)} style={style}>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width={this.props.size} height={this.props.size}>
|
|
{fill}
|
|
{stroke}
|
|
</svg>
|
|
</div>
|
|
);
|
|
}
|
|
}
|