Skip to content

Commit

Permalink
Create a new class to work with pentagrams (star polygons)
Browse files Browse the repository at this point in the history
  • Loading branch information
elchininet committed Sep 29, 2024
1 parent b8df40c commit 301496b
Show file tree
Hide file tree
Showing 12 changed files with 702 additions and 28 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [3.8.0] - 2024-09-29

- Create a new class to work with pentagrams (star polygons)

## [3.7.3] - 2023-08-12

- Fix ESM types
Expand Down
277 changes: 261 additions & 16 deletions README.md

Large diffs are not rendered by default.

12 changes: 10 additions & 2 deletions demo/demo2/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default ( IsometricModule, container ) => {

const { IsometricCanvas, IsometricPath, IsometricRectangle, PlaneView } = IsometricModule;
const { IsometricCanvas, IsometricPath, IsometricRectangle, IsometricPentagram, PlaneView } = IsometricModule;

const cube = new IsometricCanvas({
container,
Expand All @@ -27,6 +27,7 @@ export default ( IsometricModule, container ) => {
};

const topPiece = new IsometricPath();
const star = new IsometricPentagram({ radius: 0.35, planeView: PlaneView.TOP, right: 0.5, left: 0.5, top: 1});
const rightPiece = new IsometricRectangle({...commonProps, planeView: PlaneView.FRONT, right: 1});
const leftPiece = new IsometricRectangle({...commonProps, planeView: PlaneView.SIDE, left: 1});

Expand All @@ -48,6 +49,13 @@ export default ( IsometricModule, container ) => {
})
.addAnimation(colorAnimationProps);

star
.addAnimation({
property: 'top',
duration,
values: [1, 0.5, 1]
});

rightPiece
.addAnimation(rectangleAnimationProps)
.addAnimation(colorAnimationProps);
Expand All @@ -64,6 +72,6 @@ export default ( IsometricModule, container ) => {
}
});

cube.addChildren(topPiece, rightPiece, leftPiece);
cube.addChildren(topPiece, rightPiece, leftPiece, star);

};
2 changes: 1 addition & 1 deletion docs/scripts/bundle.js

Large diffs are not rendered by default.

232 changes: 232 additions & 0 deletions src/@classes/public/IsometricPentagram/IsometricPentagram.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import {
Command,
PlaneView,
SVG_ELEMENTS,
SVG_NAMESPACE,
} from '@constants';
import {
IsometricPoint,
LinePoint,
CommandPoint,
SVGPositionableProperties,
SVGPentagramProperties,
SVGPentagramAnimation,
SVGAnimationObject
} from '@types';
import {
getSVGPath,
translateCommandPoints,
addSVGProperties,
isSVGProperty
} from '@utils/svg';
import { IsometricShapeAbstract } from '@classes/abstract/IsometricShapeAbstract';
import {
IsometricPentagramProps,
GetPentagramPathArguments
} from './types';

export class IsometricPentagram extends IsometricShapeAbstract {

public constructor(props: IsometricPentagramProps) {
const { radius, rotation = 0, ...rest } = props;
// Exclude the next line from the coverage reports
// Check https://github.com/microsoft/TypeScript/issues/13029
/* istanbul ignore next */
super(rest);
this._radius = radius;
this._rotation = rotation;
}

private _radius: number;
private _rotation: number;

private _points = 5;
private _sector = 2 * Math.PI / this._points;
private _halfSector = this._sector / 2;
private _ratio = 2 / (3 + Math.sqrt(this._points));

protected getCommands(args?: GetPentagramPathArguments): CommandPoint[] {
const right = args?.right || this.right;
const left = args?.left || this.left;
const top = args?.top || this.top;
const radius = args?.radius || this.radius;
const rotation = args?.rotation || this.rotation;
const coordinates = this.get2DCoordinates(radius, rotation);
const commands: LinePoint[] = [];
switch(this.planeView) {
case PlaneView.FRONT:
coordinates.forEach((point: IsometricPoint, index: number): void => {
commands.push({
command: index === 0
? Command.move
: Command.line,
point: {
r: 0,
l: point.x,
t: point.y
}
});
});
break;
case PlaneView.SIDE:
coordinates.forEach((point: IsometricPoint, index: number): void => {
commands.push({
command: index === 0
? Command.move
: Command.line,
point: {
r: point.x,
l: 0,
t: point.y
}
});
});
break;
case PlaneView.TOP:
coordinates.forEach((point: IsometricPoint, index: number): void => {
commands.push({
command: index === 0
? Command.move
: Command.line,
point: {
r: - point.x,
l: - point.y,
t: 0
}
});
});
break;
}
translateCommandPoints(commands, right, left, top);
return commands;
}

private getRadianAngle(angle: number): number {
return angle * Math.PI / 180;
}

private getInnerRadius(radius: number): number {
return radius * this._ratio;
}

private get2DCoordinates(radius: number, rotation: number): IsometricPoint[] {
const innerRadius = this.getInnerRadius(radius);
return [...Array(this._points)].reduce((points: IsometricPoint[], _undefined: undefined, index: number) => {
const angle = index * this._sector + 2 * Math.PI - this.getRadianAngle(rotation);
const innerAngle = angle + this._halfSector;
const oX = Math.sin(angle) * radius;
const oY = Math.cos(angle) * radius;
const iX = Math.sin(innerAngle) * innerRadius;
const iY = Math.cos(innerAngle) * innerRadius;
return [
...points,
{ x: oX, y: oY },
{ x: iX, y: iY }
];
}, []);
}

private getPentagramPath(args: GetPentagramPathArguments): string {
const commands = this.getCommands(args);
return getSVGPath(
commands,
this.data.centerX,
this.data.centerY,
this.data.scale,
true
);
}

protected updateSubClassAnimations(): void {

this.animations.forEach((animation: SVGAnimationObject): void => {

const isNativeSVGProperty = isSVGProperty(animation.property);

if (!isNativeSVGProperty) {

const props = {
right: this.right,
left: this.left,
top: this.top,
radius: this.radius,
rotation: this.rotation
};

if (Object.prototype.hasOwnProperty.call(props, animation.property)) {

const property = animation.property as SVGPositionableProperties | SVGPentagramProperties;
let properties: Record<string, string>;

if (animation.values) {

if (Array.isArray(animation.values)) {
properties = {
values: animation.values.map((value: string | number): string => {
const modifiedArgs = { ...props };
modifiedArgs[property] = +value;
return this.getPentagramPath(modifiedArgs);
}).join(';')
};
} else {
const modifiedArgs = { ...props };
modifiedArgs[property] = +animation.values;
properties = {
values: this.getPentagramPath(modifiedArgs)
};
}

} else {
const fromArgs = { ...props };
const toArgs = { ...props };
fromArgs[property] = +animation.from;
toArgs[property] = +animation.to;
properties = {
from: this.getPentagramPath(fromArgs),
to: this.getPentagramPath(toArgs)
};
}

if (!animation.element) {
animation.element = document.createElementNS(SVG_NAMESPACE, SVG_ELEMENTS.animate) as SVGAnimateElement;
}

if (!animation.element.parentNode) {
this.element.appendChild(animation.element);
}

this.addAnimationBasicProperties('d', animation);

addSVGProperties(animation.element, properties);

}

}

});

}

public get radius(): number {
return this._radius;
}

public set radius(value: number) {
this._radius = value;
this.update();
}

public get rotation(): number {
return this._rotation;
}

public set rotation(value: number) {
this._rotation = value;
this.update();
}

public addAnimation(animation: SVGPentagramAnimation): this {
return super.addAnimation(animation);
}

}
2 changes: 2 additions & 0 deletions src/@classes/public/IsometricPentagram/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { IsometricPentagram } from './IsometricPentagram';
export { IsometricPentagramProps } from './types';
14 changes: 14 additions & 0 deletions src/@classes/public/IsometricPentagram/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { IsometricShapeProps } from '@classes/abstract/IsometricShapeAbstract';

export interface IsometricPentagramProps extends IsometricShapeProps {
radius: number;
rotation?: number;
}

export interface GetPentagramPathArguments {
right: number;
left: number;
top: number;
radius: number;
rotation: number;
}
5 changes: 5 additions & 0 deletions src/@types/type-modules/svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type SVGPathProperties = 'path';
export type SVGPositionableProperties = 'left' | 'right' | 'top';
export type SVGRectangleProperties = 'width' | 'height';
export type SVGCircleProperties = 'radius';
export type SVGPentagramProperties = 'radius' | 'rotation';
export type SVGTextProperties = 'rotation';
export type SVGAnimationProperties = SVGProperties | SVGPathProperties | SVGPositionableProperties | SVGRectangleProperties | SVGCircleProperties | SVGTextProperties;
export type SVGNativeProperties = 'fill' | 'fill-opacity' | 'stroke' | 'stroke-opacity' | 'stroke-width' | 'd';
Expand Down Expand Up @@ -47,6 +48,10 @@ export type SVGCircleAnimation = SVGAnimation & {
property: SVGProperties | SVGPositionableProperties | SVGCircleProperties;
}

export type SVGPentagramAnimation = SVGAnimation & {
property: SVGProperties | SVGPositionableProperties | SVGPentagramProperties;
}

export type SVGAnimationObject = SVGAnimation & {
element?: SVGAnimateElement;
};
Expand Down
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ export {
export {
SVGPathAnimation,
SVGRectangleAnimation,
SVGCircleAnimation
SVGCircleAnimation,
SVGPentagramAnimation
} from '@types';
export { IsometricGraphicProps } from '@classes/abstract/IsometricGraphicAbstract';
export { IsometricCanvas, IsometricCanvasProps } from '@classes/public/IsometricCanvas';
export { IsometricGroup, IsometricGroupProps } from '@classes/public/IsometricGroup';
export { IsometricRectangle, IsometricRectangleProps } from '@classes/public/IsometricRectangle';
export { IsometricCircle, IsometricCircleProps } from '@classes/public/IsometricCircle';
export { IsometricPentagram, IsometricPentagramProps } from '@classes/public/IsometricPentagram';
export { IsometricPath, IsometricPathProps } from '@classes/public/IsometricPath';
export { IsometricText, IsometricTextProps } from '@classes/public/IsometricText';
Loading

0 comments on commit 301496b

Please sign in to comment.