feat: add EllipseRing shape

This commit is contained in:
iaosee 2023-04-25 03:36:40 +00:00
parent 4009e6bd11
commit 9788357d3c
5 changed files with 270 additions and 0 deletions

View File

@ -7,6 +7,7 @@ import { Arc } from './shapes/Arc';
import { Arrow } from './shapes/Arrow'; import { Arrow } from './shapes/Arrow';
import { Circle } from './shapes/Circle'; import { Circle } from './shapes/Circle';
import { Ellipse } from './shapes/Ellipse'; import { Ellipse } from './shapes/Ellipse';
import { EllipseRing } from './shapes/EllipseRing';
import { Image } from './shapes/Image'; import { Image } from './shapes/Image';
import { Label, Tag } from './shapes/Label'; import { Label, Tag } from './shapes/Label';
import { Line } from './shapes/Line'; import { Line } from './shapes/Line';
@ -47,6 +48,7 @@ export const Konva = Core.Util._assign(Core, {
Arrow, Arrow,
Circle, Circle,
Ellipse, Ellipse,
EllipseRing,
Image, Image,
Label, Label,
Tag, Tag,

View File

@ -110,6 +110,8 @@ declare namespace Konva {
export const Ellipse: typeof import('./shapes/Ellipse').Ellipse; export const Ellipse: typeof import('./shapes/Ellipse').Ellipse;
export type Ellipse = import('./shapes/Ellipse').Ellipse; export type Ellipse = import('./shapes/Ellipse').Ellipse;
export type EllipseConfig = import('./shapes/Ellipse').EllipseConfig; 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 const Image: typeof import('./shapes/Image').Image;
export type Image = import('./shapes/Image').Image; export type Image = import('./shapes/Image').Image;
export type ImageConfig = import('./shapes/Image').ImageConfig; export type ImageConfig = import('./shapes/Image').ImageConfig;

143
src/shapes/EllipseRing.ts Normal file
View File

@ -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());

View File

@ -33,6 +33,7 @@
import './unit/Text-test.ts'; import './unit/Text-test.ts';
import './unit/Blob-test.ts'; import './unit/Blob-test.ts';
import './unit/Ellipse-test.ts'; import './unit/Ellipse-test.ts';
import './unit/EllipseRing-test.ts';
import './unit/Polygon-test.ts'; import './unit/Polygon-test.ts';
import './unit/Spline-test.ts'; import './unit/Spline-test.ts';
import './unit/Sprite-test.ts'; import './unit/Sprite-test.ts';

View File

@ -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);
});
});