mirror of
https://github.com/fluxscape/fluxscape.git
synced 2026-01-12 23:32:55 +01:00
Initial commit
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>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { Circle } from './Circle';
|
||||
|
||||
export default {
|
||||
title: 'CATEGORY_HERE/Circle',
|
||||
component: Circle,
|
||||
argTypes: {}
|
||||
} as ComponentMeta<typeof Circle>;
|
||||
|
||||
const Template: ComponentStory<typeof Circle> = (args) => <Circle {...args} />;
|
||||
|
||||
export const Common = Template.bind({});
|
||||
Common.args = {};
|
||||
@@ -0,0 +1,130 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './Circle';
|
||||
Reference in New Issue
Block a user