This commit is contained in:
poanse 2026-01-06 17:11:02 +03:00
parent 055c8192d7
commit 89e6af0b90
9 changed files with 78 additions and 39 deletions

View file

@ -23,6 +23,7 @@ export class Context {
view: TaskmapView;
nodePositionsCalculator: NodePositionsCalculator;
pressedButtonCode = $state(-1);
draggedTaskId = $state(NoTaskId);
selectedTaskId = $state(NoTaskId);
focusedTaskId = $state(RootTaskId);
toolbarStatus = $state(StatusCode.DRAFT);
@ -64,6 +65,10 @@ export class Context {
this.updateTaskPositions();
}
public setDraggedTaskId = (id: number) => {
this.draggedTaskId = id;
};
public setScale(scale: number) {
this.scale = scale;
}
@ -74,16 +79,21 @@ export class Context {
public isTaskHidden(taskId: TaskId): boolean {
const task = this.projectData.getTask(taskId);
const ancestors = this.projectData
const ancestorTasks = this.projectData.getAncestors(taskId);
const focusedAncestorIds = this.projectData
.getAncestors(this.focusedTaskId)
.map((t) => t.taskId);
const descendants = this.projectData.getDescendants(this.focusedTaskId);
const focusedDescendantIds = this.projectData.getDescendants(
this.focusedTaskId,
);
return (
task.deleted ||
ancestorTasks.some((t) => t.hidden) ||
!(
task.taskId == this.focusedTaskId ||
ancestors.contains(task.taskId) ||
descendants.contains(task.taskId)
focusedAncestorIds.contains(task.taskId) ||
focusedDescendantIds.contains(task.taskId)
)
);
}
@ -150,10 +160,8 @@ export class Context {
);
if (this.taskDraggingManager.isDragging) {
[
this.taskDraggingManager.draggedTaskId,
...this.projectData.getDescendants(
this.taskDraggingManager.draggedTaskId,
),
this.draggedTaskId,
...this.projectData.getDescendants(this.draggedTaskId),
].forEach((t) => {
const v = this.positions.get(t);
if (v !== undefined) {
@ -181,7 +189,7 @@ export class Context {
}
// dragging
if (this.taskDraggingManager.draggedTaskId !== NoTaskId) {
if (this.draggedTaskId !== NoTaskId) {
const draggingDelta = V2.mult(
{
x: this.taskDraggingManager.deltaX,
@ -190,12 +198,16 @@ export class Context {
1 / this.scale,
);
const draggedTaskIds = this.projectData.getDescendants(
this.taskDraggingManager.draggedTaskId,
this.draggedTaskId,
);
this.taskPositions
.filter((t) => draggedTaskIds.contains(t.taskId))
.forEach((t) => {
if (t.tween !== null && t.tween !== undefined) {
if (
t.tween !== null &&
t.tween !== undefined &&
this.positions.has(t.taskId)
) {
t.tween.stiffness = 1;
t.tween.damping = 1;
t.tween.set(
@ -217,7 +229,7 @@ export class Context {
private updateDraggedTaskPriority() {
// Если порядок тасок по оси Y отличается от приоритетов, то меняем приоритеты и пересчитываем порядок
const draggedParentId = this.projectData.getTask(
this.taskDraggingManager.draggedTaskId,
this.draggedTaskId,
).parentId;
const orderedSiblings = this.taskPositions
.filter((t) =>
@ -228,16 +240,13 @@ export class Context {
.sort((a, b) => a.tween?.target.y! - b.tween?.target.y!)
.map((t) => t.taskId);
const newPriority = orderedSiblings.findIndex(
(t) => t == this.taskDraggingManager.draggedTaskId,
(t) => t == this.draggedTaskId,
);
const oldPriority = this.projectData.getTask(
this.taskDraggingManager.draggedTaskId,
this.draggedTaskId,
).priority;
if (newPriority != oldPriority) {
this.projectData.setPriority(
this.taskDraggingManager.draggedTaskId,
newPriority,
);
this.projectData.setPriority(this.draggedTaskId, newPriority);
return true;
}
return false;

View file

@ -1,5 +1,4 @@
import { MouseDown } from "./types";
import { NoTaskId } from "./NodePositionsCalculator";
export class DraggingManager {
mouseCodes: MouseDown[];
@ -9,17 +8,12 @@ export class DraggingManager {
startY = 0;
deltaX = $state(0);
deltaY = $state(0);
draggedTaskId = $state(NoTaskId);
constructor(mouseCodes: MouseDown[]) {
this.mouseCodes = [];
this.mouseCodes.push(...mouseCodes);
}
public setDraggedTaskId = (id: number) => {
this.draggedTaskId = id;
};
public onPointerDown = (e: PointerEvent) => {
console.log("DraggingManager pointerDown");
this.mouseDown = e.button as MouseDown;
@ -35,7 +29,6 @@ export class DraggingManager {
public onPointerUp = (e: PointerEvent) => {
console.log(`DraggingManager pointerUp: ${this.deltaX}`);
this.setDraggedTaskId(NoTaskId);
this.mouseDown = MouseDown.NONE;
this.isDragging = false;
this.deltaX = 0;

View file

@ -68,9 +68,28 @@ export class NodePositionsCalculator {
const positions: Map<TaskId, Vector2> = new Map<TaskId, Vector2>();
positions.set(NoTaskId, V2.Zero);
tasks.forEach((t) => {
const parentPos = positions.get(t.parentId)!;
const relativePos = parentFramePositions.get(t.taskId)!;
const sortedTasksDepthAsc = [...tasks].sort((a, b) => {
if (b.depth !== a.depth) {
return a.depth - b.depth;
} else if (a.parentId !== b.parentId) {
return a.parentId - b.parentId;
} else {
return a.priority - b.priority;
}
});
sortedTasksDepthAsc.forEach((t) => {
const parentPos = positions.get(t.parentId);
const relativePos = parentFramePositions.get(t.taskId);
if (parentPos == undefined) {
throw new Error(
`No parent position for task ${t.taskId} with parent ${t.parentId}`,
);
}
if (relativePos == undefined) {
throw new Error(
`No relative position for task ${t.taskId} with parent ${t.parentId}`,
);
}
positions.set(t.taskId, V2.add(parentPos, relativePos));
});
@ -103,7 +122,7 @@ export class NodePositionsCalculator {
});
const taskById = new Map<TaskId, TaskData>();
tasks.forEach((t) => taskById.set(t.taskId, t));
sortedTasks.forEach((t) => taskById.set(t.taskId, t));
const childrenIdsByParentId: Map<TaskId, TaskId[]> = new Map<
TaskId,

View file

@ -48,7 +48,7 @@ export class ProjectData {
this.tasks.push({
taskId: id,
parentId: parentId,
status: StatusCode.DRAFT,
status: StatusCode.READY,
name: "default",
deleted: false,
hidden: false,

View file

@ -2,14 +2,17 @@
import { TASK_SIZE } from "../Constants";
import { StatusCode } from "../types";
import { Context } from "../Context.svelte.js";
import {NoTaskId} from "../NodePositionsCalculator";
const { taskId, context }: { taskId: number, context: Context } = $props();
let taskData = $derived(context.projectData.getTask(taskId));
let entered = $state(false);
function addButtonPressed(event: MouseEvent) {
function addButtonPressed(event: PointerEvent) {
context.addTask(taskId);
context.taskDraggingManager.onPointerUp(event);
context.setDraggedTaskId(NoTaskId);
event.stopPropagation();
}
</script>
@ -30,6 +33,7 @@
class:ready={taskData.status === StatusCode.READY}
class:in-progress={taskData.status === StatusCode.IN_PROGRESS}
class:done={taskData.status === StatusCode.DONE}
onpointerdown={()=>{}}
onpointerup={addButtonPressed}
viewBox="0 0 24 24"
>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { TASK_SIZE } from "../Constants";
import { Context } from "../Context.svelte.js";
import {ParentToChildHorizontalShift} from "../NodePositionsCalculator";
import {NoTaskId, ParentToChildHorizontalShift} from "../NodePositionsCalculator";
import { Eye, EyeClosed } from 'lucide-svelte';
const { taskId, context }: { taskId: number, context: Context } = $props();
@ -9,9 +9,12 @@
let taskData = $derived(context.projectData.getTask(taskId));
let entered = $state(false);
function hidePressed(event: MouseEvent) {
function hidePressed(event: PointerEvent) {
context.projectData.toggleHidden(taskId);
event.stopPropagation();
context.taskDraggingManager.onPointerUp(event);
context.setDraggedTaskId(NoTaskId);
context.updateTaskPositions();
}
</script>
@ -26,9 +29,15 @@
"
>
{#if taskData.hidden}
<EyeClosed onclick={hidePressed}/>
<EyeClosed
onpointerdown={()=>{}}
onpointerup={hidePressed}
/>
{:else if entered && !taskData.hidden}
<Eye onclick={hidePressed}/>
<Eye
onpointerdown={()=>{}}
onpointerup={hidePressed}
/>
{/if}
</div>
{/if}
@ -46,7 +55,7 @@
/* Ensure the transparent area still catches mouse events */
background: transparent;
pointer-events: auto;
pointer-events: visible;
cursor: pointer;
:global(svg) {

View file

@ -4,6 +4,7 @@
import TaskText from "./TaskText.svelte";
import AddTaskButton from "./AddTaskButton.svelte";
import HideBranchButton from "./HideBranchButton.svelte";
import {NoTaskId} from "../NodePositionsCalculator";
const {
taskId,
@ -46,6 +47,7 @@
// input.disabled = false;
}
context.taskDraggingManager.onPointerUp(event);
context.setDraggedTaskId(NoTaskId);
context.updateTaskPositions();
event.stopPropagation();
}
@ -74,7 +76,7 @@
onmouseenter={() => isHovered = true}
onmouseleave={() => isHovered = false}
onpointerdown={(event: PointerEvent) => {
context.taskDraggingManager.setDraggedTaskId(taskId);
context.setDraggedTaskId(taskId);
}}
onpointerup={onPointerUp}
onblur={() => finishEditing(true)}
@ -95,8 +97,8 @@
</div>
{#if !context.taskDraggingManager.isDragging}
<AddTaskButton {context} {taskId} />
<HideBranchButton {context} {taskId} />
{/if}
<HideBranchButton {context} {taskId} />
</div>
{/key}
{/if}

View file

@ -3,6 +3,7 @@
import {MarkdownRenderer, Component, App, type TFile} from "obsidian";
import {LinkSuggest} from "../LinkSuggest";
import type {Context} from "../Context.svelte.js";
import {NoTaskId} from "../NodePositionsCalculator";
// PROPS
let {
@ -63,6 +64,7 @@
return;
}
context.taskDraggingManager.onPointerUp(e);
context.setDraggedTaskId(NoTaskId);
console.log('task text clicked');
const target = e.target as HTMLElement;

View file

@ -6,7 +6,7 @@
import type {Context} from "../Context.svelte.js";
import {MouseDown} from "../types";
import Connection from "./Connection.svelte";
import {RootTaskId, V2} from "../NodePositionsCalculator";
import {NoTaskId, RootTaskId, V2} from "../NodePositionsCalculator";
import {TASK_SIZE} from "../Constants";
let {context}: {context: Context} = $props();
@ -110,6 +110,7 @@
function onpointerup(e: PointerEvent) {
console.log('handlePointerUp', e.pointerId, e.button);
context.taskDraggingManager.onPointerUp(e);
context.setDraggedTaskId(NoTaskId);
context.updateTaskPositions();
if (e.button as MouseDown == MouseDown.MIDDLE && isDragging) {
// Release the pointer capture