Skip to content

Commit

Permalink
feat: ✨ add EllipseRing shape
Browse files Browse the repository at this point in the history
  • Loading branch information
iaosee committed Dec 5, 2024
1 parent 4009e6b commit 9788357
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/_FullInternals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Arc } from './shapes/Arc';
import { Arrow } from './shapes/Arrow';
import { Circle } from './shapes/Circle';
import { Ellipse } from './shapes/Ellipse';
import { EllipseRing } from './shapes/EllipseRing';
import { Image } from './shapes/Image';
import { Label, Tag } from './shapes/Label';
import { Line } from './shapes/Line';
Expand Down Expand Up @@ -47,6 +48,7 @@ export const Konva = Core.Util._assign(Core, {
Arrow,
Circle,
Ellipse,
EllipseRing,
Image,
Label,
Tag,
Expand Down
2 changes: 2 additions & 0 deletions src/index-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ declare namespace Konva {
export const Ellipse: typeof import('./shapes/Ellipse').Ellipse;
export type Ellipse = import('./shapes/Ellipse').Ellipse;
export type EllipseConfig = import('./shapes/Ellipse').EllipseConfig;
export type EllipseRing = import('./shapes/EllipseRing').EllipseRing;
export type EllipseRingConfig = import('./shapes/EllipseRing').EllipseRingConfig;
export const Image: typeof import('./shapes/Image').Image;
export type Image = import('./shapes/Image').Image;
export type ImageConfig = import('./shapes/Image').ImageConfig;
Expand Down
143 changes: 143 additions & 0 deletions src/shapes/EllipseRing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { Factory } from '../Factory';
import { Shape, ShapeConfig } from '../Shape';
import { GetSet } from '../types';
import { getNumberValidator } from '../Validators';
import { _registerNode } from '../Global';
import { Context } from '../Context';

export interface EllipseRingConfig extends ShapeConfig {
innerRadiusX: number;
innerRadiusY: number;
outerRadiusX: number;
outerRadiusY: number;
}

const PIx2 = Math.PI * 2;

/**
* EllipseRing constructor
* @constructor
* @augments Konva.Shape
* @memberof Konva
* @param {Object} config
* @param {Number} config.innerRadiusX
* @param {Number} config.innerRadiusY
* @param {Number} config.outerRadiusX
* @param {Number} config.outerRadiusY
* @@shapeParams
* @@nodeParams
* @example
* var EllipseRing = new Konva.EllipseRing({
* innerRadiusX: 40,
* innerRadiusY: 20,
* outerRadiusX: 80,
* outerRadiusY: 40,
* fill: 'red',
* stroke: 'black',
* strokeWidth: 5
* });
*/
export class EllipseRing extends Shape<EllipseRingConfig> {

_sceneFunc(context: Context) {
const irx = this.innerRadiusX();
const iry = this.innerRadiusY();
const orx = this.outerRadiusX();
const ory = this.outerRadiusY();

context.beginPath();
// context.ellipse(0, 0, orx - ringWidth, ory - ringWidth, 0, 0, PIx2, false);
context.ellipse(0, 0, irx, iry, 0, 0, PIx2, false);
context.moveTo(orx, 0);
context.ellipse(0, 0, orx, ory, 0, PIx2, 0, true);

context.closePath();
context.fillStrokeShape(this);
}

getWidth() {
return this.outerRadiusX() * 2;
}

getHeight() {
return this.outerRadiusY() * 2;
}

setWidth(width: number) {
this.outerRadiusX(width / 2);
}

setHeight(height: number) {
this.outerRadiusY(height / 2);
}

innerRadiusX: GetSet<number, this>;
innerRadiusY: GetSet<number, this>;
outerRadiusX: GetSet<number, this>;
outerRadiusY: GetSet<number, this>;
}

EllipseRing.prototype.className = 'EllipseRing';
EllipseRing.prototype._centroid = true;
EllipseRing.prototype._attrsAffectingSize = ['innerRadiusX', 'innerRadiusY', 'outerRadiusX', 'outerRadiusY'];
_registerNode(EllipseRing);

/**
* get/set innerRadiusX
* @method
* @name Konva.Ring#innerRadiusX
* @param {Number} innerRadiusX
* @returns {Number}
* @example
* // get inner radiusX
* var innerRadiusX = ring.innerRadiusX();
*
* // set inner radiusX
* ring.innerRadiusX(20);
*/
Factory.addGetterSetter(EllipseRing, 'innerRadiusX', 0, getNumberValidator());

/**
* get/set innerRadiusY
* @method
* @name Konva.Ring#innerRadiusY
* @param {Number} innerRadiusY
* @returns {Number}
* @example
* // get inner radiusY
* var innerRadiusY = ring.innerRadiusY();
*
* // set inner radiusY
* ring.innerRadiusY(20);
*/
Factory.addGetterSetter(EllipseRing, 'innerRadiusY', 0, getNumberValidator());

/**
* get/set outerRadiusX
* @name Konva.Ring#outerRadiusX
* @method
* @param {Number} outerRadiusX
* @returns {Number}
* @example
* // get outer radiusX
* var outerRadiusX = ring.outerRadiusX();
*
* // set outer radiusX
* ring.outerRadiusX(20);
*/
Factory.addGetterSetter(EllipseRing, 'outerRadiusX', 0, getNumberValidator());

/**
* get/set outerRadiusY
* @name Konva.Ring#outerRadiusY
* @method
* @param {Number} outerRadiusY
* @returns {Number}
* @example
* // get outer radiusY
* var outerRadiusY = ring.outerRadiusY();
*
* // set outer radiusY
* ring.outerRadiusY(20);
*/
Factory.addGetterSetter(EllipseRing, 'outerRadiusY', 0, getNumberValidator());
1 change: 1 addition & 0 deletions test/unit-tests.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import './unit/Text-test.ts';
import './unit/Blob-test.ts';
import './unit/Ellipse-test.ts';
import './unit/EllipseRing-test.ts';
import './unit/Polygon-test.ts';
import './unit/Spline-test.ts';
import './unit/Sprite-test.ts';
Expand Down
122 changes: 122 additions & 0 deletions test/unit/EllipseRing-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { assert } from 'chai';

import {
addStage,
Konva,
createCanvas,
compareLayerAndCanvas,
compareLayers,
} from './test-utils';

describe('EllipseRing', function () {
// ======================================================
it('add ellipse ring', function () {
var stage = addStage();
var layer = new Konva.Layer();
var ellipse = new Konva.EllipseRing({
x: stage.width() / 2,
y: stage.height() / 2,
innerRadiusX: 40,
innerRadiusY: 20,
outerRadiusX: 80,
outerRadiusY: 40,
fill: 'green',
stroke: 'black',
strokeWidth: 8,
});
layer.add(ellipse);
stage.add(layer);
assert.equal(ellipse.getClassName(), 'EllipseRing');

var trace = layer.getContext().getTrace();

assert.equal(
trace,
'clearRect(0,0,578,200);save();transform(1,0,0,1,289,100);beginPath();ellipse(0,0,40,20,0,0,6.283,false);moveTo(80,0);ellipse(0,0,80,40,0,6.283,0,true);closePath();fillStyle=green;fill();lineWidth=8;strokeStyle=black;stroke();restore();'
);
});

// ======================================================
it('attrs sync', function () {
var stage = addStage();
var layer = new Konva.Layer();
var ellipse = new Konva.EllipseRing({
x: stage.width() / 2,
y: stage.height() / 2,
innerRadiusX: 40,
innerRadiusY: 20,
outerRadiusX: 80,
outerRadiusY: 40,
fill: 'green',
stroke: 'black',
strokeWidth: 8,
});
layer.add(ellipse);
stage.add(layer);

assert.equal(ellipse.getWidth(), 160);
assert.equal(ellipse.getHeight(), 80);

ellipse.setWidth(100);
assert.equal(ellipse.innerRadiusX(), 40);
assert.equal(ellipse.innerRadiusY(), 20);
assert.equal(ellipse.outerRadiusX(), 50);
assert.equal(ellipse.outerRadiusY(), 40);

ellipse.setHeight(120);
assert.equal(ellipse.innerRadiusX(), 40);
assert.equal(ellipse.innerRadiusY(), 20);
assert.equal(ellipse.outerRadiusX(), 50);
assert.equal(ellipse.outerRadiusY(), 60);
});

it('getSelfRect', function () {
var stage = addStage();
var layer = new Konva.Layer();
var ellipse = new Konva.EllipseRing({
x: stage.width() / 2,
y: stage.height() / 2,
innerRadiusX: 40,
innerRadiusY: 20,
outerRadiusX: 80,
outerRadiusY: 40,
fill: 'green',
stroke: 'black',
strokeWidth: 8,
});
layer.add(ellipse);
stage.add(layer);

assert.deepEqual(ellipse.getSelfRect(), {
x: -80,
y: -40,
width: 160,
height: 80,
});
});

it('cache', function () {
var stage = addStage();
var layer = new Konva.Layer();
var ellipse = new Konva.EllipseRing({
x: stage.width() / 2,
y: stage.height() / 2,
innerRadiusX: 40,
innerRadiusY: 20,
outerRadiusX: 80,
outerRadiusY: 40,
fill: 'green',
stroke: 'black',
strokeWidth: 8,
});

layer.add(ellipse);
stage.add(layer);

var layer2 = layer.clone();
stage.add(layer2);
layer2.hide();

compareLayers(layer, layer2);
});
});

0 comments on commit 9788357

Please sign in to comment.