Skip to content

Commit

Permalink
refactor: Use shape handler's interface for tree shapes
Browse files Browse the repository at this point in the history
  • Loading branch information
miyanokomiya committed Feb 9, 2024
1 parent 2620c07 commit ced273a
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import {
isValidTreeNode,
newTreeNodeMovingHandler,
} from "./treeHandler";
import { newShapeComposite } from "./shapeComposite";
import { createShape, getCommonStruct } from "../shapes";
import { TreeNodeShape } from "../shapes/tree/treeNode";
import { TreeRootShape } from "../shapes/tree/treeRoot";
import { newShapeComposite } from "../shapeComposite";
import { createShape, getCommonStruct } from "../../shapes";
import { TreeNodeShape } from "../../shapes/tree/treeNode";
import { TreeRootShape } from "../../shapes/tree/treeRoot";
import { generateKeyBetween } from "fractional-indexing";

const root = createShape<TreeRootShape>(getCommonStruct, "tree_root", {
Expand Down Expand Up @@ -80,12 +80,12 @@ const shapeComposite = newShapeComposite({
});

describe("newTreeNodeMovingHandler", () => {
describe("moveTest: horizontal", () => {
describe("hitTest: horizontal", () => {
test("should return node moving result: move inside the siblings", () => {
const target = newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" });
expect(target.moveTest({ x: 80, y: -10 })).toEqual(undefined);
expect(target.moveTest({ x: 50, y: 40 })).toEqual(undefined);
expect(target.moveTest({ x: 50, y: 60 })).toEqual({
expect(target.hitTest({ x: 80, y: -10 }, 1)).toEqual(undefined);
expect(target.hitTest({ x: 50, y: 40 }, 1)).toEqual(undefined);
expect(target.hitTest({ x: 50, y: 60 }, 1)).toEqual({
treeParentId: "root",
direction: 1,
findex: generateKeyBetween(b.findex, null),
Expand All @@ -94,12 +94,12 @@ describe("newTreeNodeMovingHandler", () => {

test("should return node moving result: move to other parent", () => {
const target = newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" });
expect(target.moveTest({ x: 110, y: 50 })).toEqual({
expect(target.hitTest({ x: 110, y: 50 }, 1)).toEqual({
treeParentId: "b",
direction: 1,
findex: generateKeyBetween(null, bb.findex),
});
expect(target.moveTest({ x: 110, y: 60 })).toEqual({
expect(target.hitTest({ x: 110, y: 60 }, 1)).toEqual({
treeParentId: "b",
direction: 1,
findex: generateKeyBetween(bb.findex, null),
Expand All @@ -108,7 +108,7 @@ describe("newTreeNodeMovingHandler", () => {

test("should return node moving result: become the first child", () => {
const target = newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" });
expect(target.moveTest({ x: 150, y: 50 })).toEqual({
expect(target.hitTest({ x: 150, y: 50 }, 1)).toEqual({
treeParentId: "bb",
direction: 1,
findex: generateKeyBetween(bb.findex, null),
Expand All @@ -117,7 +117,7 @@ describe("newTreeNodeMovingHandler", () => {

test("should return node moving result: should not move to own children", () => {
const target = newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" });
expect(target.moveTest({ x: 110, y: -50 })).toEqual({
expect(target.hitTest({ x: 110, y: -50 }, 1)).toEqual({
treeParentId: "b",
direction: 1,
findex: generateKeyBetween(null, bb.findex),
Expand All @@ -126,17 +126,17 @@ describe("newTreeNodeMovingHandler", () => {

test("should return node moving result: switch direction", () => {
const target = newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" });
expect(target.moveTest({ x: -50, y: 10 })).toEqual({
expect(target.hitTest({ x: -50, y: 10 }, 1)).toEqual({
treeParentId: "root",
direction: 3,
findex: generateKeyBetween(ia.findex, null),
});
expect(target.moveTest({ x: -50, y: 2 })).toEqual({
expect(target.hitTest({ x: -50, y: 2 }, 1)).toEqual({
treeParentId: "root",
direction: 3,
findex: generateKeyBetween(null, ia.findex),
});
expect(target.moveTest({ x: -60, y: 0 })).toEqual({
expect(target.hitTest({ x: -60, y: 0 }, 1)).toEqual({
treeParentId: "ia",
direction: 3,
findex: generateKeyBetween(ia.findex, null),
Expand All @@ -152,12 +152,12 @@ describe("newTreeNodeMovingHandler", () => {
}),
targetId: "a",
});
expect(target1.moveTest({ x: -50, y: 0 })).toEqual({
expect(target1.hitTest({ x: -50, y: 0 }, 1)).toEqual({
treeParentId: "root",
direction: 3,
findex: generateKeyBetween(root.findex, null),
});
expect(target1.moveTest({ x: 50, y: 0 })).toEqual(undefined);
expect(target1.hitTest({ x: 50, y: 0 }, 1)).toEqual(undefined);

const target2 = newTreeNodeMovingHandler({
getShapeComposite: () =>
Expand All @@ -167,16 +167,16 @@ describe("newTreeNodeMovingHandler", () => {
}),
targetId: "ia",
});
expect(target2.moveTest({ x: 50, y: 0 })).toEqual({
expect(target2.hitTest({ x: 50, y: 0 }, 1)).toEqual({
treeParentId: "root",
direction: 1,
findex: generateKeyBetween(root.findex, null),
});
expect(target2.moveTest({ x: -50, y: 0 })).toEqual(undefined);
expect(target2.hitTest({ x: -50, y: 0 }, 1)).toEqual(undefined);
});
});

describe("moveTest: vertical", () => {
describe("hitTest: vertical", () => {
const a = createShape<TreeNodeShape>(getCommonStruct, "tree_node", {
id: "a",
findex: generateKeyBetween(root.findex, null),
Expand Down Expand Up @@ -234,9 +234,9 @@ describe("newTreeNodeMovingHandler", () => {

test("should return node moving result: move inside the siblings", () => {
const target = newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" });
expect(target.moveTest({ x: -10, y: 80 })).toEqual(undefined);
expect(target.moveTest({ x: 40, y: 50 })).toEqual(undefined);
expect(target.moveTest({ x: 60, y: 50 })).toEqual({
expect(target.hitTest({ x: -10, y: 80 }, 1)).toEqual(undefined);
expect(target.hitTest({ x: 40, y: 50 }, 1)).toEqual(undefined);
expect(target.hitTest({ x: 60, y: 50 }, 1)).toEqual({
treeParentId: "root",
direction: 2,
findex: generateKeyBetween(b.findex, null),
Expand All @@ -245,12 +245,12 @@ describe("newTreeNodeMovingHandler", () => {

test("should return node moving result: move to other parent", () => {
const target = newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" });
expect(target.moveTest({ x: 50, y: 110 })).toEqual({
expect(target.hitTest({ x: 50, y: 110 }, 1)).toEqual({
treeParentId: "b",
direction: 2,
findex: generateKeyBetween(null, bb.findex),
});
expect(target.moveTest({ x: 60, y: 110 })).toEqual({
expect(target.hitTest({ x: 60, y: 110 }, 1)).toEqual({
treeParentId: "b",
direction: 2,
findex: generateKeyBetween(bb.findex, null),
Expand All @@ -259,7 +259,7 @@ describe("newTreeNodeMovingHandler", () => {

test("should return node moving result: become the first child", () => {
const target = newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" });
expect(target.moveTest({ x: 50, y: 150 })).toEqual({
expect(target.hitTest({ x: 50, y: 150 }, 1)).toEqual({
treeParentId: "bb",
direction: 2,
findex: generateKeyBetween(bb.findex, null),
Expand All @@ -268,7 +268,7 @@ describe("newTreeNodeMovingHandler", () => {

test("should return node moving result: should not move to own children", () => {
const target = newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" });
expect(target.moveTest({ x: -50, y: 110 })).toEqual({
expect(target.hitTest({ x: -50, y: 110 }, 1)).toEqual({
treeParentId: "b",
direction: 2,
findex: generateKeyBetween(null, bb.findex),
Expand All @@ -277,17 +277,17 @@ describe("newTreeNodeMovingHandler", () => {

test("should return node moving result: switch direction", () => {
const target = newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" });
expect(target.moveTest({ x: 10, y: -50 })).toEqual({
expect(target.hitTest({ x: 10, y: -50 }, 1)).toEqual({
treeParentId: "root",
direction: 0,
findex: generateKeyBetween(ia.findex, null),
});
expect(target.moveTest({ x: 2, y: -50 })).toEqual({
expect(target.hitTest({ x: 2, y: -50 }, 1)).toEqual({
treeParentId: "root",
direction: 0,
findex: generateKeyBetween(null, ia.findex),
});
expect(target.moveTest({ x: 0, y: -60 })).toEqual({
expect(target.hitTest({ x: 0, y: -60 }, 1)).toEqual({
treeParentId: "ia",
direction: 0,
findex: generateKeyBetween(ia.findex, null),
Expand All @@ -303,12 +303,12 @@ describe("newTreeNodeMovingHandler", () => {
}),
targetId: "a",
});
expect(target1.moveTest({ x: 0, y: -50 })).toEqual({
expect(target1.hitTest({ x: 0, y: -50 }, 1)).toEqual({
treeParentId: "root",
direction: 0,
findex: generateKeyBetween(root.findex, null),
});
expect(target1.moveTest({ x: 0, y: 50 })).toEqual(undefined);
expect(target1.hitTest({ x: 0, y: 50 }, 1)).toEqual(undefined);

const target2 = newTreeNodeMovingHandler({
getShapeComposite: () =>
Expand All @@ -318,28 +318,12 @@ describe("newTreeNodeMovingHandler", () => {
}),
targetId: "ia",
});
expect(target2.moveTest({ x: 0, y: 50 })).toEqual({
expect(target2.hitTest({ x: 0, y: 50 }, 1)).toEqual({
treeParentId: "root",
direction: 2,
findex: generateKeyBetween(root.findex, null),
});
expect(target2.moveTest({ x: 0, y: -50 })).toEqual(undefined);
});
});

describe("branchIds", () => {
test("should return branch ids belonging to the target shape", () => {
expect(newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "a" }).branchIds).toEqual([
"a",
"aa",
]);
expect(newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "b" }).branchIds).toEqual([
"b",
"bb",
]);
expect(newTreeNodeMovingHandler({ getShapeComposite: () => shapeComposite, targetId: "bb" }).branchIds).toEqual([
"bb",
]);
expect(target2.hitTest({ x: 0, y: -50 }, 1)).toEqual(undefined);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { IRectangle, IVec2, getDistance, getRectCenter, isSame } from "okageo";
import { getWrapperRect } from "../shapes";
import { TreeNodeShape, getBoxAlignByDirection, isTreeNodeShape } from "../shapes/tree/treeNode";
import { TreeRootShape, isTreeRootShape } from "../shapes/tree/treeRoot";
import { ShapeComposite } from "./shapeComposite";
import { Direction4, EntityPatchInfo, Shape, StyleScheme } from "../models";
import { applyFillStyle } from "../utils/fillStyle";
import { TAU, getDistanceBetweenPointAndRect } from "../utils/geometry";
import { applyStrokeStyle } from "../utils/strokeStyle";
import { CHILD_MARGIN, SIBLING_MARGIN, TreeLayoutNode, treeLayout } from "../utils/layouts/tree";
import { flatTree, getAllBranchIds, getTree } from "../utils/tree";
import { TreeShapeBase, isTreeShapeBase } from "../shapes/tree/core";
import { generateKeyBetweenAllowSame } from "../utils/findex";
import { pickMinItem } from "../utils/commons";
import { getWrapperRect } from "../../shapes";
import { TreeNodeShape, getBoxAlignByDirection, isTreeNodeShape } from "../../shapes/tree/treeNode";
import { TreeRootShape, isTreeRootShape } from "../../shapes/tree/treeRoot";
import { ShapeComposite } from "../shapeComposite";
import { Direction4, EntityPatchInfo, Shape, StyleScheme } from "../../models";
import { applyFillStyle } from "../../utils/fillStyle";
import { TAU, getDistanceBetweenPointAndRect } from "../../utils/geometry";
import { applyStrokeStyle } from "../../utils/strokeStyle";
import { CHILD_MARGIN, SIBLING_MARGIN, TreeLayoutNode, treeLayout } from "../../utils/layouts/tree";
import { flatTree, getAllBranchIds, getTree } from "../../utils/tree";
import { TreeShapeBase, isTreeShapeBase } from "../../shapes/tree/core";
import { generateKeyBetweenAllowSame } from "../../utils/findex";
import { pickMinItem } from "../../utils/commons";
import { defineShapeHandler } from "./core";

const ANCHOR_SIZE = 10;
const ANCHOR_MARGIN = 30;
Expand All @@ -38,7 +39,7 @@ interface Option {
targetId: string;
}

export function newTreeHandler(option: Option) {
export const newTreeHandler = defineShapeHandler<TreeHitResult, Option>((option) => {
const shapeComposite = option.getShapeComposite();
const shape = shapeComposite.shapeMap[option.targetId] as TreeRootShape | TreeNodeShape;
const isRoot = isTreeRootShape(shape);
Expand Down Expand Up @@ -207,17 +208,17 @@ export function newTreeHandler(option: Option) {
}
}

return { hitTest, render };
}
export type TreeHandler = ReturnType<typeof newTreeHandler>;

export function isSameTreeHitResult(a?: TreeHitResult, b?: TreeHitResult): boolean {
if (a && b) {
return a?.direction === b?.direction && isSame(a.p, b.p);
}

return !a && !b;
}
return {
hitTest,
render,
isSameHitResult: (a, b) => {
if (a && b) {
return a?.direction === b?.direction && isSame(a.p, b.p);
}
return !a && !b;
},
};
});

export interface TreeNodeMovingResult {
treeParentId: string;
Expand All @@ -228,7 +229,7 @@ export interface TreeNodeMovingResult {
/**
* Suppose a tree can contain either vertical or horizontal branches.
*/
export function newTreeNodeMovingHandler(option: Option) {
export const newTreeNodeMovingHandler = defineShapeHandler<TreeNodeMovingResult, Option>((option) => {
const shapeComposite = option.getShapeComposite();
const shape = shapeComposite.shapeMap[option.targetId] as TreeNodeShape;
const root = shapeComposite.shapeMap[shape.parentId!] as TreeRootShape;
Expand All @@ -246,7 +247,7 @@ export function newTreeNodeMovingHandler(option: Option) {
getWrapperRect(shapeComposite.getShapeStruct, shapeComposite.shapeMap[id]),
]);

function moveTest(p: IVec2): TreeNodeMovingResult | undefined {
function hitTest(p: IVec2): TreeNodeMovingResult | undefined {
if (rects.length === 0) return;

const evaluated = rects.map<[string, IRectangle, number]>(([id, rect]) => [
Expand Down Expand Up @@ -395,9 +396,14 @@ export function newTreeNodeMovingHandler(option: Option) {
);
}

return { moveTest, render, branchIds: Array.from(ownBranchIdSet) };
}
export type TreeNodeMovingHandler = ReturnType<typeof newTreeNodeMovingHandler>;
return {
hitTest,
render,
isSameHitResult: (a, b) => {
return a?.treeParentId === b?.treeParentId && a?.direction === b?.direction && a?.findex === b?.findex;
},
};
});

function getTreeNodeMovingResultToInsertSibling(
shapeComposite: ShapeComposite,
Expand Down
2 changes: 1 addition & 1 deletion src/composables/shapeLayoutHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getBoardLayoutPatchFunctions } from "./boardHandler";
import { getConnectedLinePatch } from "./connectedLineHandler";
import { getLineLabelPatch } from "./lineLabelHandler";
import { ShapeComposite, getNextShapeComposite } from "./shapeComposite";
import { getTreeLayoutPatchFunctions } from "./treeHandler";
import { getTreeLayoutPatchFunctions } from "./shapeHandlers/treeHandler";

/**
* Genaral porpus patch function to recalculate all layouts and automatic adjustments.
Expand Down
Loading

0 comments on commit ced273a

Please sign in to comment.