Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/1234/keep-label-on-selection #3465

Merged
merged 7 commits into from
Jan 12, 2024
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/)
- Clarify sonar user token question [#3445](https://github.com/MaibornWolff/codecharta/pull/3445)
- Changed the `--user` flag to `--user-token` in SonarImporter [#3445](https://github.com/MaibornWolff/codecharta/pull/3445)
- Changed the interactive dialog of `modify` to prompt user for single action to perform [#3448](https://github.com/MaibornWolff/codecharta/pull/3448)
- Selected buildings now keep their label until they are unselected [#3465](https://github.com/MaibornWolff/codecharta/pull/3465)

### Fixed 🐞

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { ThreeSceneService } from "./threeViewer/threeSceneService"
import { ThreeRendererService } from "./threeViewer/threeRenderer.service"
import { ViewCubeMouseEventsService } from "../viewCube/viewCube.mouseEvents.service"
import { CodeMapBuilding } from "./rendering/codeMapBuilding"
import { CODE_MAP_BUILDING, CONSTANT_HIGHLIGHT, TEST_FILE_WITH_PATHS, TEST_NODES } from "../../util/dataMocks"
import { BlacklistItem, CcState, CodeMapNode, Node } from "../../codeCharta.model"
import { NodeDecorator } from "../../util/nodeDecorator"
import { klona } from "klona"
Expand All @@ -19,6 +18,7 @@ import { setRightClickedNodeData } from "../../state/store/appStatus/rightClicke
import { State, Store } from "@ngrx/store"
import { MockStore, provideMockStore } from "@ngrx/store/testing"
import { defaultState } from "../../state/store/state.manager"
import { CODE_MAP_BUILDING, CODE_MAP_BUILDING_TS_NODE, CONSTANT_HIGHLIGHT, TEST_FILE_WITH_PATHS, TEST_NODES } from "../../util/dataMocks"

jest.mock("../../state/selectors/accumulatedData/idToNode.selector", () => ({
idToNodeSelector: jest.fn()
Expand Down Expand Up @@ -521,6 +521,9 @@ describe("codeMapMouseEventService", () => {

it("should call selectBuilding when no building is selected", () => {
threeSceneService.getSelectedBuilding = jest.fn()
threeSceneService.getLabelForHoveredNode = jest.fn()
threeSceneService.animateLabel = jest.fn()

codeMapMouseEventService["intersectedBuilding"] = codeMapBuilding

codeMapMouseEventService.onDocumentMouseUp(event)
Expand All @@ -530,6 +533,9 @@ describe("codeMapMouseEventService", () => {

it("should call selectBuilding when a new building is selected", () => {
threeSceneService.getSelectedBuilding = jest.fn().mockReturnValue(new CodeMapBuilding(200, null, null, null))
threeSceneService.getLabelForHoveredNode = jest.fn()
threeSceneService.animateLabel = jest.fn()

codeMapMouseEventService["intersectedBuilding"] = codeMapBuilding

codeMapMouseEventService.onDocumentMouseUp(event)
Expand All @@ -548,6 +554,9 @@ describe("codeMapMouseEventService", () => {
})

it("should not call clearSelection, when the mouse has moved less or exact 3 pixels but a building is currently being clicked upon", () => {
threeSceneService.getLabelForHoveredNode = jest.fn()
threeSceneService.animateLabel = jest.fn()

codeMapMouseEventService.onDocumentMouseMove(event)
codeMapMouseEventService.onDocumentMouseDown(event)
codeMapMouseEventService.onDocumentMouseMove({ clientX: 10, clientY: 17 } as MouseEvent)
Expand Down Expand Up @@ -817,7 +826,7 @@ describe("codeMapMouseEventService", () => {
threeSceneService.getLabelForHoveredNode = jest.fn()
codeMapLabelService.addLeafLabel = jest.fn()

codeMapMouseEventService["drawTemporaryLabelFor"](codeMapBuilding, null)
codeMapMouseEventService["drawTemporaryLabelFor"](codeMapBuilding)
const nodeHeight = codeMapBuilding.node.height + Math.abs(codeMapBuilding.node.heightDelta ?? 0)

expect(threeSceneService.getLabelForHoveredNode).toHaveBeenCalled()
Expand All @@ -829,10 +838,76 @@ describe("codeMapMouseEventService", () => {
threeSceneService.getLabelForHoveredNode = jest.fn()
codeMapLabelService.addLeafLabel = jest.fn()

codeMapMouseEventService["drawTemporaryLabelFor"](codeMapBuilding, null)
codeMapMouseEventService["drawTemporaryLabelFor"](codeMapBuilding)

expect(threeSceneService.getLabelForHoveredNode).toHaveBeenCalled()
expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledWith(codeMapBuilding.node, 0, true)
})
})

describe("labelForSelectedBuilding", () => {
it("should create a label when selecting a building", () => {
threeSceneService.getLabelForHoveredNode = jest.fn()
threeSceneService.animateLabel = jest.fn()
codeMapLabelService.addLeafLabel = jest.fn()

codeMapMouseEventService["drawLabelForSelected"](codeMapBuilding)

expect(threeSceneService.getLabelForHoveredNode).toHaveBeenCalled()
expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledWith(codeMapBuilding.node, 0, true)
expect(codeMapMouseEventService["temporaryLabelForSelectedBuilding"]).toEqual(codeMapBuilding.node)
})

it("should remove the label when a previously selected building is unselected", () => {
threeSceneService.getLabelForHoveredNode = jest.fn()
threeSceneService.animateLabel = jest.fn()
codeMapLabelService.clearTemporaryLabel = jest.fn()
codeMapMouseEventService["drawLabelForSelected"](codeMapBuilding)

codeMapMouseEventService["clearLabelForSelected"]()

expect(codeMapLabelService.clearTemporaryLabel).toHaveBeenCalledWith(codeMapBuilding.node)
expect(codeMapMouseEventService["temporaryLabelForSelectedBuilding"]).toBeNull()
})

it("should remove the old and create the new label when selected building is changed", () => {
const oldSelection = codeMapBuilding
const newSelection = CODE_MAP_BUILDING_TS_NODE

threeSceneService.getLabelForHoveredNode = jest.fn()
threeSceneService.animateLabel = jest.fn()
codeMapLabelService.clearTemporaryLabel = jest.fn()
codeMapLabelService.addLeafLabel = jest.fn()

codeMapMouseEventService["drawLabelForSelected"](codeMapBuilding)

codeMapMouseEventService["intersectedBuilding"] = newSelection
codeMapMouseEventService["onLeftClick"]()

expect(codeMapMouseEventService["temporaryLabelForSelectedBuilding"]).not.toEqual(oldSelection.node)
expect(codeMapMouseEventService["temporaryLabelForSelectedBuilding"]).toEqual(newSelection.node)
expect(codeMapLabelService.clearTemporaryLabel).toHaveBeenCalledWith(codeMapBuilding.node)
expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledWith(oldSelection.node, 0, true)
expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledWith(newSelection.node, 0, true)
expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledTimes(2)
})

it("should keep the label when clicking on the already selected building", () => {
threeSceneService.getLabelForHoveredNode = jest.fn()
threeSceneService.animateLabel = jest.fn()
codeMapMouseEventService["clearTemporaryLabel"] = jest.fn()
codeMapMouseEventService["drawLabelForSelected"] = jest.fn()

codeMapMouseEventService["drawLabelForSelected"](codeMapBuilding)
const referenceLabel = codeMapMouseEventService["temporaryLabelForSelectedBuilding"]

codeMapMouseEventService["intersectedBuilding"] = codeMapBuilding
codeMapMouseEventService["onLeftClick"]()

expect(codeMapMouseEventService["drawLabelForSelected"]).toHaveBeenCalledWith(codeMapBuilding)
expect(codeMapMouseEventService["drawLabelForSelected"]).toHaveBeenCalledTimes(2)
expect(codeMapMouseEventService["clearTemporaryLabel"]).not.toHaveBeenCalled()
expect(codeMapMouseEventService["temporaryLabelForSelectedBuilding"]).toEqual(referenceLabel)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class CodeMapMouseEventService implements OnDestroy {
private isMoving = false
private raycaster = new Raycaster()
private temporaryLabelForBuilding = null
private temporaryLabelForSelectedBuilding = null
private subscriptions = [
this.store
.select(visibleFileStatesSelector)
Expand Down Expand Up @@ -216,17 +217,14 @@ export class CodeMapMouseEventService implements OnDestroy {
const to = this.intersectedBuilding

if (from?.id !== to?.id) {
if (this.temporaryLabelForBuilding !== null) {
this.codeMapLabelService.clearTemporaryLabel(this.temporaryLabelForBuilding)
this.temporaryLabelForBuilding = null
}
this.clearTemporaryLabel()

this.threeSceneService.resetLabel()
this.unhoverBuilding()
if (to && !this.isGrabbingOrMoving()) {
if (to.node.isLeaf) {
const labelForBuilding =
this.threeSceneService.getLabelForHoveredNode(to, labels) ?? this.drawTemporaryLabelFor(to, labels)
this.threeSceneService.getLabelForHoveredNode(to, labels) ?? this.drawTemporaryLabelFor(to)
this.threeSceneService.animateLabel(labelForBuilding, this.raycaster, labels)
}
this.hoverBuilding(to)
Expand All @@ -236,11 +234,11 @@ export class CodeMapMouseEventService implements OnDestroy {
}
}

private drawTemporaryLabelFor(codeMapBuilding: CodeMapBuilding, labels: Object3D[]) {
private drawTemporaryLabelFor(codeMapBuilding: CodeMapBuilding) {
const enforceLabel = true
this.codeMapLabelService.addLeafLabel(codeMapBuilding.node, 0, enforceLabel)

labels = this.threeSceneService.labels?.children
const labels = this.threeSceneService.labels?.children
const labelForBuilding = this.threeSceneService.getLabelForHoveredNode(codeMapBuilding, labels)
this.temporaryLabelForBuilding = codeMapBuilding.node

Expand Down Expand Up @@ -355,14 +353,42 @@ export class CodeMapMouseEventService implements OnDestroy {
if (!this.hasMouseMovedMoreThanThreePixels(this.mouseOnLastClick)) {
if (this.intersectedBuilding) {
this.threeSceneService.selectBuilding(this.intersectedBuilding)
this.drawLabelForSelected(this.intersectedBuilding)
} else {
this.threeSceneService.clearSelection()
this.clearLabelForSelected()
}
this.threeSceneService.clearConstantHighlight()
}
this.threeRendererService.render()
}

private drawLabelForSelected(codeMapBuilding: CodeMapBuilding) {
this.clearTemporaryLabel()
if (this.temporaryLabelForSelectedBuilding !== null) {
this.codeMapLabelService.clearTemporaryLabel(this.temporaryLabelForSelectedBuilding)
}
if (!codeMapBuilding.node.isLeaf) {
return
}

this.codeMapLabelService.addLeafLabel(codeMapBuilding.node, 0, true)

const labels = this.threeSceneService.labels?.children
const labelForBuilding = this.threeSceneService.getLabelForHoveredNode(codeMapBuilding, labels)
this.threeSceneService.animateLabel(labelForBuilding, this.raycaster, labels)

this.temporaryLabelForSelectedBuilding = codeMapBuilding.node
return labelForBuilding
}

private clearLabelForSelected() {
if (this.temporaryLabelForSelectedBuilding !== null) {
this.codeMapLabelService.clearTemporaryLabel(this.temporaryLabelForSelectedBuilding)
this.temporaryLabelForSelectedBuilding = null
}
}

private hasMouseMovedMoreThanThreePixels({ x, y }: Coordinates) {
return (
Math.abs(this.mouse.x - x) > this.THRESHOLD_FOR_MOUSE_MOVEMENT_TRACKING ||
Expand Down
Loading