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

Highlight nodes onclick file explorer #3488

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/)

## [unreleased] (Added 🚀 | Changed | Removed 🗑 | Fixed 🐞 | Chore 👨‍💻 👩‍💻)

### Added 🚀

- Highlight building on-click of file in explorer [#3488](https://github.com/MaibornWolff/codecharta/pull/3488)

### Fixed 🐞

- Fix buildings inability to be completely red in delta mode [#3439](https://github.com/MaibornWolff/codecharta/pull/3439)
Expand Down
Expand Up @@ -287,11 +287,11 @@ describe("codeMapMouseEventService", () => {
expect(codeMapMouseEventService["isMoving"]).toBe(false)
codeMapMouseEventService.onDocumentMouseMove({ clientX: 2, clientY: 3 } as MouseEvent)

codeMapMouseEventService["temporaryLabelForBuilding"] = label.clone()
codeMapMouseEventService["labelHoveredBuilding"] = label.clone()
codeMapMouseEventService.updateHovering()

expect(threeSceneService["highlightedLabel"]).toBeNull()
expect(codeMapMouseEventService["temporaryLabelForBuilding"]).toBeNull()
expect(codeMapMouseEventService["labelHoveredBuilding"]).toBeNull()
expect(label["material"].opacity).toEqual(0.7)
expect(label.position).not.toEqual(animatedLabelPosition)
})
Expand All @@ -307,11 +307,11 @@ describe("codeMapMouseEventService", () => {
expect(codeMapMouseEventService["isMoving"]).toBe(true)
codeMapMouseEventService.onDocumentMouseMove({ clientX: 3, clientY: 4 } as MouseEvent)

codeMapMouseEventService["temporaryLabelForBuilding"] = label.clone()
codeMapMouseEventService["labelHoveredBuilding"] = label.clone()
codeMapMouseEventService.updateHovering()

expect(threeSceneService["highlightedLabel"]).toBeNull()
expect(codeMapMouseEventService["temporaryLabelForBuilding"]).toBeNull()
expect(codeMapMouseEventService["labelHoveredBuilding"]).toBeNull()
expect(label["material"].opacity).toEqual(0.7)
expect(label.position).not.toEqual(animatedLabelPosition)
})
Expand Down Expand Up @@ -415,7 +415,7 @@ describe("codeMapMouseEventService", () => {
})

it("should call clearTemporaryLabel and remove temporary label when a new building is hovered", () => {
codeMapMouseEventService["temporaryLabelForBuilding"] = CODE_MAP_BUILDING.node
codeMapMouseEventService["labelHoveredBuilding"] = CODE_MAP_BUILDING.node

threeSceneService.getMapMesh = jest.fn().mockReturnValue({
checkMouseRayMeshIntersection: jest.fn().mockReturnValue(CODE_MAP_BUILDING)
Expand All @@ -424,7 +424,7 @@ describe("codeMapMouseEventService", () => {
codeMapMouseEventService.updateHovering()

expect(codeMapLabelService.clearTemporaryLabel).toHaveBeenCalled()
expect(codeMapLabelService["temporaryLabelForBuilding"]).not.toEqual(CODE_MAP_BUILDING.node)
expect(codeMapLabelService["labelHoveredBuilding"]).not.toEqual(CODE_MAP_BUILDING.node)
})

it("should hover a node when an intersection was found and the cursor is set to pointing and call getLabelForHoveredNode", () => {
Expand Down Expand Up @@ -821,12 +821,12 @@ describe("codeMapMouseEventService", () => {
})
})

describe("drawTemporaryLabelFor", () => {
describe("drawLabelHoveredBuilding", () => {
it("should call addLeafLabel on codeMapLabelService with given node and the corresponding height that is different from 0", () => {
threeSceneService.getLabelForHoveredNode = jest.fn()
codeMapLabelService.addLeafLabel = jest.fn()

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

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

codeMapMouseEventService["drawTemporaryLabelFor"](codeMapBuilding)
codeMapMouseEventService["drawLabelHoveredBuilding"](codeMapBuilding)

expect(threeSceneService.getLabelForHoveredNode).toHaveBeenCalled()
expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledWith(codeMapBuilding.node, 0, true)
Expand All @@ -851,23 +851,23 @@ describe("codeMapMouseEventService", () => {
threeSceneService.animateLabel = jest.fn()
codeMapLabelService.addLeafLabel = jest.fn()

codeMapMouseEventService["drawLabelForSelected"](codeMapBuilding)
codeMapMouseEventService["drawLabelSelectedBuilding"](codeMapBuilding)

expect(threeSceneService.getLabelForHoveredNode).toHaveBeenCalled()
expect(codeMapLabelService.addLeafLabel).toHaveBeenCalledWith(codeMapBuilding.node, 0, true)
expect(codeMapMouseEventService["temporaryLabelForSelectedBuilding"]).toEqual(codeMapBuilding.node)
expect(codeMapMouseEventService["labelSelectedBuilding"]).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["drawLabelSelectedBuilding"](codeMapBuilding)

codeMapMouseEventService["clearLabelForSelected"]()
codeMapMouseEventService["clearLabelSelectedBuilding"]()

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

it("should remove the old and create the new label when selected building is changed", () => {
Expand All @@ -879,13 +879,13 @@ describe("codeMapMouseEventService", () => {
codeMapLabelService.clearTemporaryLabel = jest.fn()
codeMapLabelService.addLeafLabel = jest.fn()

codeMapMouseEventService["drawLabelForSelected"](codeMapBuilding)
codeMapMouseEventService["drawLabelSelectedBuilding"](codeMapBuilding)

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

expect(codeMapMouseEventService["temporaryLabelForSelectedBuilding"]).not.toEqual(oldSelection.node)
expect(codeMapMouseEventService["temporaryLabelForSelectedBuilding"]).toEqual(newSelection.node)
expect(codeMapMouseEventService["labelSelectedBuilding"]).not.toEqual(oldSelection.node)
expect(codeMapMouseEventService["labelSelectedBuilding"]).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)
Expand All @@ -896,18 +896,18 @@ describe("codeMapMouseEventService", () => {
threeSceneService.getLabelForHoveredNode = jest.fn()
threeSceneService.animateLabel = jest.fn()
codeMapMouseEventService["clearTemporaryLabel"] = jest.fn()
codeMapMouseEventService["drawLabelForSelected"] = jest.fn()
codeMapMouseEventService["drawLabelSelectedBuilding"] = jest.fn()

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

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

expect(codeMapMouseEventService["drawLabelForSelected"]).toHaveBeenCalledWith(codeMapBuilding)
expect(codeMapMouseEventService["drawLabelForSelected"]).toHaveBeenCalledTimes(2)
expect(codeMapMouseEventService["drawLabelSelectedBuilding"]).toHaveBeenCalledWith(codeMapBuilding)
expect(codeMapMouseEventService["drawLabelSelectedBuilding"]).toHaveBeenCalledTimes(2)
expect(codeMapMouseEventService["clearTemporaryLabel"]).not.toHaveBeenCalled()
expect(codeMapMouseEventService["temporaryLabelForSelectedBuilding"]).toEqual(referenceLabel)
expect(codeMapMouseEventService["labelSelectedBuilding"]).toEqual(referenceLabel)
})
})
})
100 changes: 52 additions & 48 deletions visualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.ts
Expand Up @@ -50,8 +50,8 @@ export class CodeMapMouseEventService implements OnDestroy {
private isGrabbing = false
private isMoving = false
private raycaster = new Raycaster()
private temporaryLabelForBuilding = null
private temporaryLabelForSelectedBuilding = null
private labelHoveredBuilding = null
private labelSelectedBuilding = null
private subscriptions = [
this.store
.select(visibleFileStatesSelector)
Expand Down Expand Up @@ -151,12 +151,12 @@ export class CodeMapMouseEventService implements OnDestroy {
onFilesSelectionChanged() {
this.threeSceneService.clearSelection()
this.threeSceneService.clearConstantHighlight()
this.clearTemporaryLabel()
this.clearLabelHoveredBuilding()
}

onBlacklistChanged(blacklist: BlacklistItem[]) {
const selectedBuilding = this.threeSceneService.getSelectedBuilding()
this.clearTemporaryLabel()
this.clearLabelHoveredBuilding()
if (selectedBuilding) {
const isSelectedBuildingBlacklisted = isPathHiddenOrExcluded(selectedBuilding.node.path, blacklist)

Expand All @@ -167,20 +167,13 @@ export class CodeMapMouseEventService implements OnDestroy {
this.unhoverBuilding()
}

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

updateHovering() {
if (this.hasMouseMoved(this.oldMouse)) {
const labels = this.threeSceneService.labels?.children

if (this.isGrabbingOrMoving()) {
this.threeSceneService.resetLabel()
this.clearTemporaryLabel()
this.clearLabelHoveredBuilding()
this.threeRendererService.render()
return
}
Expand Down Expand Up @@ -217,34 +210,71 @@ export class CodeMapMouseEventService implements OnDestroy {
const to = this.intersectedBuilding

if (from?.id !== to?.id) {
this.clearTemporaryLabel()
this.clearLabelHoveredBuilding()

this.threeSceneService.resetLabel()
this.unhoverBuilding()
if (to && !this.isGrabbingOrMoving()) {
if (to.node.isLeaf) {
const labelForBuilding =
this.threeSceneService.getLabelForHoveredNode(to, labels) ?? this.drawTemporaryLabelFor(to)
this.threeSceneService.animateLabel(labelForBuilding, this.raycaster, labels)
}
this.setLabelHoveredLeaf(to, labels)
this.hoverBuilding(to)
}
}
}
}
}

private drawTemporaryLabelFor(codeMapBuilding: CodeMapBuilding) {
setLabelHoveredLeaf(codeMapBuilding: CodeMapBuilding, labels: Object3D[]) {
if (codeMapBuilding.node.isLeaf) {
const labelForBuilding =
this.threeSceneService.getLabelForHoveredNode(codeMapBuilding, labels) ?? this.drawLabelHoveredBuilding(codeMapBuilding)
this.threeSceneService.animateLabel(labelForBuilding, this.raycaster, labels)
}
}

drawLabelHoveredBuilding(codeMapBuilding: CodeMapBuilding) {
const enforceLabel = true
this.codeMapLabelService.addLeafLabel(codeMapBuilding.node, 0, enforceLabel)

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

return labelForBuilding
}

drawLabelSelectedBuilding(codeMapBuilding: CodeMapBuilding) {
this.clearLabelHoveredBuilding()
if (this.labelSelectedBuilding !== null) {
this.codeMapLabelService.clearTemporaryLabel(this.labelSelectedBuilding)
}
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.labelSelectedBuilding = codeMapBuilding.node
return labelForBuilding
}

clearLabelHoveredBuilding() {
if (this.labelHoveredBuilding !== null) {
this.codeMapLabelService.clearTemporaryLabel(this.labelHoveredBuilding)
this.labelHoveredBuilding = null
}
}

private clearLabelSelectedBuilding() {
if (this.labelSelectedBuilding !== null) {
this.codeMapLabelService.clearTemporaryLabel(this.labelSelectedBuilding)
this.labelSelectedBuilding = null
}
}

private EnableOrbitalsRotation(isRotation: boolean) {
this.threeViewerService.enableRotation(isRotation)
this.viewCubeMouseEvents.enableRotation(isRotation)
Expand Down Expand Up @@ -353,42 +383,16 @@ export class CodeMapMouseEventService implements OnDestroy {
if (!this.hasMouseMovedMoreThanThreePixels(this.mouseOnLastClick)) {
if (this.intersectedBuilding) {
this.threeSceneService.selectBuilding(this.intersectedBuilding)
this.drawLabelForSelected(this.intersectedBuilding)
this.drawLabelSelectedBuilding(this.intersectedBuilding)
} else {
this.threeSceneService.clearSelection()
this.clearLabelForSelected()
this.clearLabelSelectedBuilding()
}
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
Expand Up @@ -4,13 +4,12 @@ import userEvent from "@testing-library/user-event"
import { EdgeMetricData } from "../../codeCharta.model"
import { metricDataSelector } from "../../state/selectors/accumulatedData/metricData/metricData.selector"
import { isDeltaStateSelector } from "../../state/selectors/isDeltaState.selector"
import { ThreeCameraService } from "../codeMap/threeViewer/threeCamera.service"
import { ThreeOrbitControlsService } from "../codeMap/threeViewer/threeOrbitControls.service"
import { RibbonBarComponent } from "./ribbonBar.component"
import { RibbonBarModule } from "./ribbonBar.module"
import { VALID_NODE_WITH_PATH_AND_EXTENSION } from "../../util/dataMocks"
import { appReducers, setStateMiddleware } from "../../state/store/state.manager"
import { StoreModule } from "@ngrx/store"
import { CodeMapMouseEventService } from "../codeMap/codeMap.mouseEvent.service"

jest.mock("../../state/selectors/isDeltaState.selector", () => ({
isDeltaStateSelector: jest.fn()
Expand All @@ -37,10 +36,7 @@ describe("RibbonBarComponent", () => {
mockMetricDataSelector.mockImplementation(() => ({ edgeMetricData: [], nodeMetricData: [], nodeEdgeMetricsMap: new Map() }))
TestBed.configureTestingModule({
imports: [RibbonBarModule, StoreModule.forRoot(appReducers, { metaReducers: [setStateMiddleware] })],
providers: [
{ provide: ThreeCameraService, useValue: {} },
{ provide: ThreeOrbitControlsService, useValue: {} }
]
providers: [{ provide: CodeMapMouseEventService, useValue: jest.fn() }]
})
})

Expand Down
Expand Up @@ -18,7 +18,7 @@ cc-map-tree-view {
}
}

.tree-leaf .tree-element-label {
.tree-element-label {
cursor: default;
}

Expand Down
Expand Up @@ -6,7 +6,7 @@
[class.marked]="(rightClickedNodeData$ | async)?.nodeId === node.id"
(mouseenter)="onMouseEnter()"
(mouseleave)="onMouseLeave()"
(click)="toggleOpen()"
(click)="onClick()"
(contextmenu)="openNodeContextMenu($event)"
[title]="(node | areaMetricValid : (areaMetric$ | async)) ? '' : 'No Node Area for Chosen Metric'"
>
Expand Down