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 { 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,
|
||||||
|
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 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
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/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';
|
||||||
|
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