mirror of
https://github.com/konvajs/konva.git
synced 2025-08-20 04:51:04 +08:00
Merge pull request #1940 from Caden-Hornyak/feature/regular-polygon-corner-radius
Add corner radius for Regular Polygon
This commit is contained in:
commit
7b9ccd18ba
43
src/Util.ts
43
src/Util.ts
@ -1076,4 +1076,47 @@ export const Util = {
|
||||
false
|
||||
);
|
||||
},
|
||||
drawRoundedPolygonPath(
|
||||
context: Context,
|
||||
points: Vector2d[],
|
||||
sides: number,
|
||||
radius: number,
|
||||
cornerRadius: number | number[]
|
||||
) {
|
||||
radius = Math.abs(radius);
|
||||
for (let i = 0; i < sides; i++) {
|
||||
const prev = points[(i - 1 + sides) % sides];
|
||||
const curr = points[i];
|
||||
const next = points[(i + 1) % sides];
|
||||
const vec1 = {x: curr.x - prev.x, y: curr.y - prev.y};
|
||||
const vec2 = {x: next.x - curr.x, y: next.y - curr.y};
|
||||
const len1 = Math.hypot(vec1.x, vec1.y);
|
||||
const len2 = Math.hypot(vec2.x, vec2.y);
|
||||
let currCornerRadius;
|
||||
if (typeof cornerRadius === 'number') {
|
||||
currCornerRadius = cornerRadius;
|
||||
} else {
|
||||
currCornerRadius = i < cornerRadius.length ? cornerRadius[i] : 0;
|
||||
}
|
||||
const maxCornerRadius = radius * Math.cos(Math.PI / sides);
|
||||
// cornerRadius creates perfect circle at 1/2 radius
|
||||
currCornerRadius = maxCornerRadius * Math.min(1, (currCornerRadius / radius) * 2);
|
||||
const normalVec1 = {x: vec1.x / len1, y: vec1.y / len1};
|
||||
const normalVec2 = {x: vec2.x / len2, y: vec2.y / len2};
|
||||
const p1 = {
|
||||
x: curr.x - normalVec1.x * currCornerRadius,
|
||||
y: curr.y - normalVec1.y * currCornerRadius,
|
||||
};
|
||||
const p2 = {
|
||||
x: curr.x + normalVec2.x * currCornerRadius,
|
||||
y: curr.y + normalVec2.y * currCornerRadius,
|
||||
};
|
||||
if (i === 0) {
|
||||
context.moveTo(p1.x, p1.y);
|
||||
} else {
|
||||
context.lineTo(p1.x, p1.y);
|
||||
}
|
||||
context.arcTo(curr.x, curr.y, p2.x, p2.y, currCornerRadius);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,13 +1,15 @@
|
||||
import { Factory } from '../Factory';
|
||||
import { Shape, ShapeConfig } from '../Shape';
|
||||
import { GetSet, Vector2d } from '../types';
|
||||
import { getNumberValidator } from '../Validators';
|
||||
import { getNumberOrArrayOfNumbersValidator, getNumberValidator } from '../Validators';
|
||||
import { _registerNode } from '../Global';
|
||||
import { Context } from '../Context';
|
||||
import { Util } from '../Util';
|
||||
|
||||
export interface RegularPolygonConfig extends ShapeConfig {
|
||||
sides: number;
|
||||
radius: number;
|
||||
cornerRadius?: number | number[];
|
||||
}
|
||||
/**
|
||||
* RegularPolygon constructor. Examples include triangles, squares, pentagons, hexagons, etc.
|
||||
@ -15,6 +17,7 @@ export interface RegularPolygonConfig extends ShapeConfig {
|
||||
* @memberof Konva
|
||||
* @augments Konva.Shape
|
||||
* @param {Object} config
|
||||
* @param {Number} [config.cornerRadius]
|
||||
* @param {Number} config.sides
|
||||
* @param {Number} config.radius
|
||||
* @@shapeParams
|
||||
@ -32,13 +35,20 @@ export interface RegularPolygonConfig extends ShapeConfig {
|
||||
*/
|
||||
export class RegularPolygon extends Shape<RegularPolygonConfig> {
|
||||
_sceneFunc(context: Context) {
|
||||
const points = this._getPoints();
|
||||
const points = this._getPoints(),
|
||||
radius = this.radius(),
|
||||
sides = this.sides(),
|
||||
cornerRadius = this.cornerRadius();
|
||||
|
||||
context.beginPath();
|
||||
context.moveTo(points[0].x, points[0].y);
|
||||
|
||||
for (let n = 1; n < points.length; n++) {
|
||||
context.lineTo(points[n].x, points[n].y);
|
||||
if (!cornerRadius) {
|
||||
context.moveTo(points[0].x, points[0].y);
|
||||
for (let n = 1; n < points.length; n++) {
|
||||
context.lineTo(points[n].x, points[n].y);
|
||||
}
|
||||
} else {
|
||||
Util.drawRoundedPolygonPath(context, points, sides, radius, cornerRadius);
|
||||
}
|
||||
|
||||
context.closePath();
|
||||
@ -91,6 +101,7 @@ export class RegularPolygon extends Shape<RegularPolygonConfig> {
|
||||
|
||||
radius: GetSet<number, this>;
|
||||
sides: GetSet<number, this>;
|
||||
cornerRadius: GetSet<number | number[], this>;
|
||||
}
|
||||
|
||||
RegularPolygon.prototype.className = 'RegularPolygon';
|
||||
@ -127,3 +138,26 @@ Factory.addGetterSetter(RegularPolygon, 'radius', 0, getNumberValidator());
|
||||
* shape.sides(10);
|
||||
*/
|
||||
Factory.addGetterSetter(RegularPolygon, 'sides', 0, getNumberValidator());
|
||||
|
||||
/**
|
||||
* get/set corner radius
|
||||
* @method
|
||||
* @name Konva.RegularPolygon#cornerRadius
|
||||
* @param {Number} cornerRadius
|
||||
* @returns {Number}
|
||||
* @example
|
||||
* // get corner radius
|
||||
* var cornerRadius = poly.cornerRadius();
|
||||
*
|
||||
* // set corner radius
|
||||
* poly.cornerRadius(10);
|
||||
*
|
||||
* // set different corner radius values (pentagon)
|
||||
* poly.cornerRadius([0, 10, 20, 30, 40]);
|
||||
*/
|
||||
Factory.addGetterSetter(
|
||||
RegularPolygon,
|
||||
'cornerRadius',
|
||||
0,
|
||||
getNumberOrArrayOfNumbersValidator(4)
|
||||
);
|
||||
|
@ -5,6 +5,8 @@ import {
|
||||
Konva,
|
||||
cloneAndCompareLayer,
|
||||
assertAlmostEqual,
|
||||
createCanvas,
|
||||
compareLayerAndCanvas,
|
||||
} from './test-utils';
|
||||
|
||||
describe('RegularPolygon', function () {
|
||||
@ -206,4 +208,59 @@ describe('RegularPolygon', function () {
|
||||
assertAlmostEqual(box.width, 91.60254037844388);
|
||||
assertAlmostEqual(box.height, 80.00000000000003);
|
||||
});
|
||||
|
||||
// ======================================================
|
||||
it('limit corner radius', function () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
var sides = 5;
|
||||
var radius = 50;
|
||||
|
||||
var poly = new Konva.RegularPolygon({
|
||||
x: 100,
|
||||
y: 100,
|
||||
sides: sides,
|
||||
radius: radius,
|
||||
fill: 'black',
|
||||
cornerRadius: 25,
|
||||
});
|
||||
var resultCircleRadius = radius * Math.cos(Math.PI / sides);
|
||||
|
||||
layer.add(poly);
|
||||
stage.add(layer);
|
||||
|
||||
// corner radius creates perfect circle at 1/2 radius
|
||||
var canvas = createCanvas();
|
||||
var context = canvas.getContext('2d');
|
||||
context.beginPath();
|
||||
context.arc(100, 100, resultCircleRadius, 0, Math.PI * 2);
|
||||
context.fillStyle = 'black';
|
||||
context.fill();
|
||||
compareLayerAndCanvas(layer, canvas, 200);
|
||||
});
|
||||
|
||||
// ======================================================
|
||||
it('negative polygon radius with cornerRadius', function () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
|
||||
var poly = new Konva.RegularPolygon({
|
||||
x: 100,
|
||||
y: 100,
|
||||
sides: 5,
|
||||
radius: -100,
|
||||
fill: 'black',
|
||||
cornerRadius: 20,
|
||||
});
|
||||
|
||||
layer.add(poly);
|
||||
stage.add(layer);
|
||||
layer.draw();
|
||||
|
||||
var trace = layer.getContext().getTrace();
|
||||
assert.equal(
|
||||
trace,
|
||||
'clearRect(0,0,578,200);save();transform(1,0,0,1,100,100);beginPath();moveTo(26.18,80.979);arcTo(0,100,-26.18,80.979,32.361);lineTo(-68.925,49.923);arcTo(-95.106,30.902,-85.106,0.125,32.361);lineTo(-68.779,-50.125);arcTo(-58.779,-80.902,-26.418,-80.902,32.361);lineTo(26.418,-80.902);arcTo(58.779,-80.902,68.779,-50.125,32.361);lineTo(85.106,0.125);arcTo(95.106,30.902,68.925,49.923,32.361);closePath();fillStyle=black;fill();restore();clearRect(0,0,578,200);save();transform(1,0,0,1,100,100);beginPath();moveTo(26.18,80.979);arcTo(0,100,-26.18,80.979,32.361);lineTo(-68.925,49.923);arcTo(-95.106,30.902,-85.106,0.125,32.361);lineTo(-68.779,-50.125);arcTo(-58.779,-80.902,-26.418,-80.902,32.361);lineTo(26.418,-80.902);arcTo(58.779,-80.902,68.779,-50.125,32.361);lineTo(85.106,0.125);arcTo(95.106,30.902,68.925,49.923,32.361);closePath();fillStyle=black;fill();restore();'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user