Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/component/brush/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,51 @@ export function makeBrushCommonSelectorForSeries(
const selector: Record<BrushType, BrushSelectorOnBrushType> = {
lineX: getLineSelectors(0),
lineY: getLineSelectors(1),

circle: {
point: function (itemLayout, selectors, area) {
if (!itemLayout) {
return false;
}
const range = area.range as number[]; // [cx, cy, r]
const cx = range[0];
const cy = range[1];
const r = range[2];

const dx = itemLayout[0] - cx;
const dy = itemLayout[1] - cy;

// First pass: quick bounding box rejection
// Second pass: precise Euclidean squared distance
return area.boundingRect.contain(itemLayout[0], itemLayout[1])
&& (dx * dx + dy * dy <= r * r);
},
rect: function (itemLayout, selectors, area) {
if (!itemLayout) {
return false;
}
const range = area.range as number[];
const cx = range[0];
const cy = range[1];
const r = range[2];

const x = itemLayout.x;
const y = itemLayout.y;
const width = itemLayout.width;
const height = itemLayout.height;

// Find the closest point to the circle's center within the rectangle bounds
const closestX = Math.max(x, Math.min(cx, x + width));
const closestY = Math.max(y, Math.min(cy, y + height));

const dx = cx - closestX;
const dy = cy - closestY;

// Check if the distance from the closest point to the center is <= radius
return dx * dx + dy * dy <= r * r;
}
},

rect: {
point: function (itemLayout, selectors, area) {
return itemLayout && area.boundingRect.contain(itemLayout[0], itemLayout[1]);
Expand Down
56 changes: 55 additions & 1 deletion src/component/helper/BrushController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import tokens from '../../visual/tokens';
*/


export type BrushType = 'polygon' | 'rect' | 'lineX' | 'lineY';
export type BrushType = 'polygon' | 'rect' | 'lineX' | 'lineY' | 'circle';
/**
* Only for drawing (after enabledBrush).
* 'line', 'rect', 'polygon' or false
Expand Down Expand Up @@ -744,6 +744,22 @@ function getGlobalDirection2(
return globalDir.join('') as keyof typeof CURSOR_MAP;
}

function driftCircle(
controller: BrushController,
cover: BrushCover,
dx: number,
dy: number
): void {
const range = cover.__brushOption.range as BrushDimensionMinMax; // [cx, cy, radius]
const localDelta = toLocalDelta(controller, dx, dy);

range[0] += localDelta[0];
range[1] += localDelta[1];

updateCoverAfterCreation(controller, cover);
trigger(controller, {isEnd: false});
}

function driftRect(
rectRangeConverter: RectRangeConverter,
controller: BrushController,
Expand Down Expand Up @@ -1033,6 +1049,44 @@ const coverRenderers: Record<BrushType, CoverRenderer> = {

lineY: getLineRenderer(1),

circle: {
createCover: function (controller, brushOption) {
const cover = new graphic.Group() as BrushCover;

cover.add(new graphic.Circle({
name: 'main',
style: makeStyle(brushOption),
silent: true,
draggable: true,
cursor: 'move',
drift: curry(driftCircle, controller, cover),
ondragend: curry(trigger, controller, {isEnd: true})
}));

return cover;
},
getCreatingRange: function (localTrack) {
const ends = getTrackEnds(localTrack);
const cx = ends[0][0];
const cy = ends[0][1];
const dx = ends[1][0] - cx;
const dy = ends[1][1] - cy;
const r = mathPow(dx * dx + dy * dy, 0.5);

// The range structure passed to selector.ts: [centerX, centerY, radius]
return [cx, cy, r];
},
updateCoverShape: function (controller, cover, localRange: BrushDimensionMinMax, brushOption) {
(cover.childAt(0) as graphic.Circle).setShape({
cx: localRange[0],
cy: localRange[1],
r: localRange[2]
});
},
updateCommon: updateCommon,
contain: mainShapeContain
},

rect: {
createCover: function (controller, brushOption) {
function returnInput(range: BrushDimensionMinMax[]): BrushDimensionMinMax[] {
Expand Down
6 changes: 6 additions & 0 deletions src/component/helper/BrushTargetManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,9 @@ const coordConvert: Record<BrushType, ConvertCoord> = {
return p;
});
return {values: values, xyMinMax: xyMinMax};
},
circle: function (to, coordSys, rangeOrCoordRange: any) {
return { values: rangeOrCoordRange, xyMinMax: [] };
}
};

Expand Down Expand Up @@ -514,6 +517,9 @@ const diffProcessor: Record<BrushType, DiffProcess> = {
return map(values, function (item, idx) {
return [item[0] - scales[0] * refer[idx][0], item[1] - scales[1] * refer[idx][1]];
});
},
circle: function (values: any, refer: any, scales: any) {
return values;
}
};

Expand Down
3 changes: 2 additions & 1 deletion src/component/toolbox/feature/Brush.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import ExtensionAPI from '../../../core/ExtensionAPI';
import BrushModel from '../../brush/BrushModel';
import { BrushTypeUncertain } from '../../helper/BrushController';

const ICON_TYPES = ['rect', 'polygon', 'lineX', 'lineY', 'keep', 'clear'] as const;
const ICON_TYPES = ['rect', 'polygon', 'circle', 'lineX', 'lineY', 'keep', 'clear'] as const;

type IconType = typeof ICON_TYPES[number];

Expand Down Expand Up @@ -136,6 +136,7 @@ class BrushFeature extends ToolboxFeature<ToolboxBrushFeatureOption> {
/* eslint-disable */
rect: 'M7.3,34.7 M0.4,10V-0.2h9.8 M89.6,10V-0.2h-9.8 M0.4,60v10.2h9.8 M89.6,60v10.2h-9.8 M12.3,22.4V10.5h13.1 M33.6,10.5h7.8 M49.1,10.5h7.8 M77.5,22.4V10.5h-13 M12.3,31.1v8.2 M77.7,31.1v8.2 M12.3,47.6v11.9h13.1 M33.6,59.5h7.6 M49.1,59.5 h7.7 M77.5,47.6v11.9h-13', // jshint ignore:line
polygon: 'M55.2,34.9c1.7,0,3.1,1.4,3.1,3.1s-1.4,3.1-3.1,3.1 s-3.1-1.4-3.1-3.1S53.5,34.9,55.2,34.9z M50.4,51c1.7,0,3.1,1.4,3.1,3.1c0,1.7-1.4,3.1-3.1,3.1c-1.7,0-3.1-1.4-3.1-3.1 C47.3,52.4,48.7,51,50.4,51z M55.6,37.1l1.5-7.8 M60.1,13.5l1.6-8.7l-7.8,4 M59,19l-1,5.3 M24,16.1l6.4,4.9l6.4-3.3 M48.5,11.6 l-5.9,3.1 M19.1,12.8L9.7,5.1l1.1,7.7 M13.4,29.8l1,7.3l6.6,1.6 M11.6,18.4l1,6.1 M32.8,41.9 M26.6,40.4 M27.3,40.2l6.1,1.6 M49.9,52.1l-5.6-7.6l-4.9-1.2', // jshint ignore:line
circle: 'M35,10 A25,25 0 1,0 35,60 A25,25 0 1,0 35,10 Z',
lineX: 'M15.2,30 M19.7,15.6V1.9H29 M34.8,1.9H40.4 M55.3,15.6V1.9H45.9 M19.7,44.4V58.1H29 M34.8,58.1H40.4 M55.3,44.4 V58.1H45.9 M12.5,20.3l-9.4,9.6l9.6,9.8 M3.1,29.9h16.5 M62.5,20.3l9.4,9.6L62.3,39.7 M71.9,29.9H55.4', // jshint ignore:line
lineY: 'M38.8,7.7 M52.7,12h13.2v9 M65.9,26.6V32 M52.7,46.3h13.2v-9 M24.9,12H11.8v9 M11.8,26.6V32 M24.9,46.3H11.8v-9 M48.2,5.1l-9.3-9l-9.4,9.2 M38.9-3.9V12 M48.2,53.3l-9.3,9l-9.4-9.2 M38.9,62.3V46.4', // jshint ignore:line
keep: 'M4,10.5V1h10.3 M20.7,1h6.1 M33,1h6.1 M55.4,10.5V1H45.2 M4,17.3v6.6 M55.6,17.3v6.6 M4,30.5V40h10.3 M20.7,40 h6.1 M33,40h6.1 M55.4,30.5V40H45.2 M21,18.9h62.9v48.6H21V18.9z', // jshint ignore:line
Expand Down