mirror of
https://github.com/konvajs/konva.git
synced 2025-06-28 02:03:47 +08:00
feat: ✨ add EllipseRing shape
This commit is contained in:
parent
4009e6bd11
commit
9788357d3c
@ -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';
|
||||
@ -47,6 +48,7 @@ export const Konva = Core.Util._assign(Core, {
|
||||
Arrow,
|
||||
Circle,
|
||||
Ellipse,
|
||||
EllipseRing,
|
||||
Image,
|
||||
Label,
|
||||
Tag,
|
||||
|
2
src/index-types.d.ts
vendored
2
src/index-types.d.ts
vendored
@ -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;
|
||||
|
143
src/shapes/EllipseRing.ts
Normal file
143
src/shapes/EllipseRing.ts
Normal 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());
|
@ -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';
|
||||
|
122
test/unit/EllipseRing-test.ts
Normal file
122
test/unit/EllipseRing-test.ts
Normal 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);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user