Skip to content

Commit

Permalink
Fix/353/map rotation not working near cube (#1827)
Browse files Browse the repository at this point in the history
* enable cube rotation

* fixed movement near cube canvas

* Update tests (#353)

* Update CHANGELOG.md

* gradle

* Increase test coverage (#353)

Co-authored-by: Dmytro Hutkin <dmytro.hutkin@gmail.com>
Co-authored-by: DmytroHutkin <41293938+DmytroHutkin@users.noreply.github.com>
  • Loading branch information
3 people committed Mar 17, 2021
1 parent 29bf89d commit e2d1277
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/)

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

### Fixed 🐞

- It is now possible to rotate the map by rotating the view cube ([#353](https://github.com/MaibornWolff/codecharta/issues/353))

## [1.71.2] - 2021-03-16

### Fixed 🐞
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { CodeMapMesh } from "./rendering/codeMapMesh"
import { Material, Object3D, Raycaster, Vector3 } from "three"
import { CodeMapPreRenderService } from "./codeMap.preRender.service"
import { LazyLoader } from "../../util/lazyLoader"
import { ThreeViewerService } from "./threeViewer/threeViewerService"

describe("codeMapMouseEventService", () => {
let codeMapMouseEventService: CodeMapMouseEventService
Expand All @@ -46,6 +47,8 @@ describe("codeMapMouseEventService", () => {
let storeService: StoreService
let codeMapLabelService: CodeMapLabelService
let codeMapPreRenderService: CodeMapPreRenderService
let viewCubeMouseEventsService: ViewCubeMouseEventsService
let threeViewerService: ThreeViewerService

let codeMapBuilding: CodeMapBuilding
let file: CCFile
Expand Down Expand Up @@ -75,6 +78,8 @@ describe("codeMapMouseEventService", () => {
storeService = getService<StoreService>("storeService")
codeMapLabelService = getService<CodeMapLabelService>("codeMapLabelService")
codeMapPreRenderService = getService<CodeMapPreRenderService>("codeMapPreRenderService")
viewCubeMouseEventsService = getService<ViewCubeMouseEventsService>("viewCubeMouseEventsService")
threeViewerService = getService<ThreeViewerService>("threeViewerService")

codeMapBuilding = klona(CODE_MAP_BUILDING)
file = klona(TEST_FILE_WITH_PATHS)
Expand All @@ -91,7 +96,9 @@ describe("codeMapMouseEventService", () => {
threeUpdateCycleService,
storeService,
codeMapLabelService,
codeMapPreRenderService
codeMapPreRenderService,
viewCubeMouseEventsService,
threeViewerService
)

codeMapMouseEventService["oldMouse"] = { x: 1, y: 1 }
Expand Down Expand Up @@ -196,10 +203,10 @@ describe("codeMapMouseEventService", () => {
})

describe("start", () => {
it("should setup four event listeners", () => {
it("should setup six event listeners", () => {
codeMapMouseEventService.start()

expect(threeRendererService.renderer.domElement.addEventListener).toHaveBeenCalledTimes(4)
expect(threeRendererService.renderer.domElement.addEventListener).toHaveBeenCalledTimes(6)
})

it("should subscribe to event propagation", () => {
Expand Down Expand Up @@ -502,6 +509,15 @@ describe("codeMapMouseEventService", () => {
describe("onDocumentMouseUp", () => {
let event

it("should call resetIsDragging", () => {
event = { button: ClickType.LeftClick }
viewCubeMouseEventsService["resetIsDragging"] = jest.fn()

codeMapMouseEventService.onDocumentMouseUp(event)

expect(viewCubeMouseEventsService.resetIsDragging).toHaveBeenCalled()
})

describe("on left click", () => {
beforeEach(() => {
event = { button: ClickType.LeftClick, clientX: 10, clientY: 20 }
Expand Down Expand Up @@ -686,6 +702,44 @@ describe("codeMapMouseEventService", () => {
})
})

describe("onDocumentMouseEnter", () => {
it("should enable orbitals rotation", () => {
threeViewerService["enableRotation"] = jest.fn()
viewCubeMouseEventsService["enableRotation"] = jest.fn()

codeMapMouseEventService.onDocumentMouseEnter()

expect(threeViewerService.enableRotation).toHaveBeenCalledWith(true)
expect(viewCubeMouseEventsService.enableRotation).toHaveBeenCalledWith(true)
})
})

describe("onDocumentMouseLeave", () => {
it("should disable orbitals rotation", () => {
const event = { relatedTarget: {} } as MouseEvent

threeViewerService["enableRotation"] = jest.fn()
viewCubeMouseEventsService["enableRotation"] = jest.fn()

codeMapMouseEventService.onDocumentMouseLeave(event)

expect(threeViewerService.enableRotation).toHaveBeenCalledWith(false)
expect(viewCubeMouseEventsService.enableRotation).toHaveBeenCalledWith(false)
})
})

describe("onDocumentMouseMove", () => {
it("should call propagateMovement", () => {
const event = { clientX: 10, clientY: 10 } as MouseEvent

viewCubeMouseEventsService["propagateMovement"] = jest.fn()

codeMapMouseEventService.onDocumentMouseMove(event)

expect(viewCubeMouseEventsService.propagateMovement).toHaveBeenCalled()
})
})

describe("unhoverBuilding", () => {
it("should clear the highlight when to is null and constantHighlight is empty", () => {
codeMapMouseEventService["unhoverBuilding"]()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { Object3D, Raycaster } from "three"
import { CodeMapLabelService } from "./codeMap.label.service"
import { LazyLoader } from "../../util/lazyLoader"
import { CodeMapPreRenderService } from "./codeMap.preRender.service"
import { ThreeViewerService } from "./threeViewer/threeViewerService"

interface Coordinates {
x: number
Expand Down Expand Up @@ -75,7 +76,9 @@ export class CodeMapMouseEventService
private threeUpdateCycleService: ThreeUpdateCycleService,
private storeService: StoreService,
private codeMapLabelService: CodeMapLabelService,
private codeMapPreRenderService: CodeMapPreRenderService
private codeMapPreRenderService: CodeMapPreRenderService,
private viewCubeMouseEventsService: ViewCubeMouseEventsService,
private threeViewerService: ThreeViewerService
) {
this.threeUpdateCycleService.register(() => this.threeRendererService.render())
MapTreeViewLevelController.subscribeToHoverEvents(this.$rootScope, this)
Expand Down Expand Up @@ -111,6 +114,8 @@ export class CodeMapMouseEventService
this.threeRendererService.renderer.domElement.addEventListener("mouseup", event => this.onDocumentMouseUp(event))
this.threeRendererService.renderer.domElement.addEventListener("mousedown", event => this.onDocumentMouseDown(event))
this.threeRendererService.renderer.domElement.addEventListener("dblclick", () => this.onDocumentDoubleClick())
this.threeRendererService.renderer.domElement.addEventListener("mouseleave", event => this.onDocumentMouseLeave(event))
this.threeRendererService.renderer.domElement.addEventListener("mouseenter", () => this.onDocumentMouseEnter())
ViewCubeMouseEventsService.subscribeToEventPropagation(this.$rootScope, this)
}

Expand Down Expand Up @@ -253,10 +258,23 @@ export class CodeMapMouseEventService
return labelForBuilding
}

private EnableOrbitalsRotation(isRotation: boolean) {
this.threeViewerService.enableRotation(isRotation)
this.viewCubeMouseEventsService.enableRotation(isRotation)
}

onDocumentMouseEnter() {
this.EnableOrbitalsRotation(true)
}

onDocumentMouseLeave(event: MouseEvent) {
if (!(event.relatedTarget instanceof HTMLCanvasElement)) this.EnableOrbitalsRotation(false)
}

onDocumentMouseMove(event: MouseEvent) {
this.mouse.x = event.clientX
this.mouse.y = event.clientY
this.updateHovering()
this.viewCubeMouseEventsService.propagateMovement()
}

onDocumentDoubleClick() {
Expand Down Expand Up @@ -297,6 +315,7 @@ export class CodeMapMouseEventService
}

onDocumentMouseUp(event: MouseEvent) {
this.viewCubeMouseEventsService.resetIsDragging()
if (event.button === ClickType.LeftClick) {
this.onLeftClick()
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export class ThreeViewerService {
this.animate()
}

enableRotation(value: boolean) {
this.threeOrbitControlsService.controls.enableRotate = value
}

onFocusIn(event) {
if (event.target.nodeName === "INPUT") {
this.threeOrbitControlsService.controls.enableKeys = false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { IRootScopeService } from "angular"
import { Group, Mesh, PerspectiveCamera, Vector2, WebGLRenderer } from "three"
import { getService } from "../../../../mocks/ng.mockhelper"
import { ThreeOrbitControlsService } from "../codeMap/threeViewer/threeOrbitControlsService"
import { ViewCubeMouseEventsService } from "./viewCube.mouseEvents.service"
// eslint-disable-next-line no-duplicate-imports
import * as Three from "three"
import oc from "three-orbit-controls"
import { CursorType } from "../codeMap/codeMap.mouseEvent.service"

describe("ViewCubeMouseEventsService", () => {
let viewCubeMouseEventsService: ViewCubeMouseEventsService
let threeOrbitControlsService: ThreeOrbitControlsService
let $rootScope: IRootScopeService
let webGLRenderer: WebGLRenderer

Expand All @@ -19,7 +25,7 @@ describe("ViewCubeMouseEventsService", () => {
}

function rebuildService() {
viewCubeMouseEventsService = new ViewCubeMouseEventsService($rootScope)
viewCubeMouseEventsService = new ViewCubeMouseEventsService($rootScope, threeOrbitControlsService)
}

function withMockedWebGLRenderer() {
Expand Down Expand Up @@ -61,12 +67,33 @@ describe("ViewCubeMouseEventsService", () => {
}

describe("init", () => {
it("should call initRendererEventListeners", () => {
it("should call initRendererEventListeners and initOrbitalControl", () => {
viewCubeMouseEventsService["initRendererEventListeners"] = jest.fn()
viewCubeMouseEventsService["initOrbitalControl"] = jest.fn()
const camera = new PerspectiveCamera()

viewCubeMouseEventsService.init(new Group(), new PerspectiveCamera(), webGLRenderer)
viewCubeMouseEventsService.init(new Group(), camera, webGLRenderer)

expect(viewCubeMouseEventsService["initRendererEventListeners"]).toHaveBeenCalledWith(webGLRenderer)
expect(viewCubeMouseEventsService["initOrbitalControl"]).toHaveBeenCalledWith(camera, webGLRenderer)
})
})

describe("initOrbitalControl", () => {
it("should initialize controls with parameters", () => {
const camera = new PerspectiveCamera()
const OrbitControls = oc(Three)
const expectedControls = new OrbitControls(camera, webGLRenderer.domElement)
expectedControls.enableZoom = false
expectedControls.enableKeys = false
expectedControls.enablePan = false
expectedControls.rotateSpeed = 1

viewCubeMouseEventsService["initOrbitalControl"](camera, webGLRenderer)

const receivedControls = viewCubeMouseEventsService["controls"]

expect(JSON.stringify(receivedControls)).toMatch(JSON.stringify(expectedControls))
})
})

Expand All @@ -89,6 +116,45 @@ describe("ViewCubeMouseEventsService", () => {
it("should add dblclick listener", () => {
expect(webGLRenderer.domElement.addEventListener).toBeCalledWith("dblclick", expect.any(Function))
})

it("should add mouseleave listener", () => {
expect(webGLRenderer.domElement.addEventListener).toBeCalledWith("mouseleave", expect.any(Function))
})

it("should add mouseenter listener", () => {
expect(webGLRenderer.domElement.addEventListener).toBeCalledWith("mouseenter", expect.any(Function))
})
})

describe("onDocumentMouseClick", () => {
it("should call checkMouseIntersection", () => {
viewCubeMouseEventsService["checkMouseIntersection"] = jest.fn()

viewCubeMouseEventsService["onDocumentMouseClick"]({} as MouseEvent, "")

expect(viewCubeMouseEventsService["checkMouseIntersection"]).toHaveBeenCalled()
expect(viewCubeMouseEventsService["isDragging"]).toEqual(true)
})
})

describe("onWindowMouseLeave", () => {
it("should call enableRotation", () => {
viewCubeMouseEventsService["enableRotation"] = jest.fn()

viewCubeMouseEventsService["onWindowMouseLeave"]({ relatedTarget: null } as MouseEvent)

expect(viewCubeMouseEventsService["enableRotation"]).toHaveBeenCalled()
})
})

describe("onDocumentMouseEnter", () => {
it("should call enableRotation", () => {
viewCubeMouseEventsService["enableRotation"] = jest.fn()

viewCubeMouseEventsService["onDocumentMouseEnter"]()

expect(viewCubeMouseEventsService["enableRotation"]).toHaveBeenCalled()
})
})

describe("checkMouseIntersection", () => {
Expand Down Expand Up @@ -126,6 +192,19 @@ describe("ViewCubeMouseEventsService", () => {
})
})

describe("getCubeIntersectedByMouse", () => {
it("should call transformIntoCanvasVector and return null", () => {
viewCubeMouseEventsService["camera"] = new PerspectiveCamera()
viewCubeMouseEventsService["transformIntoCanvasVector"] = jest.fn().mockReturnValue(new Vector2(0, 0))
viewCubeMouseEventsService["cubeGroup"] = new Group()

const returnValue = viewCubeMouseEventsService["getCubeIntersectedByMouse"]({} as MouseEvent)

expect(viewCubeMouseEventsService["transformIntoCanvasVector"]).toHaveBeenCalled()
expect(returnValue).toEqual(null)
})
})

describe("onDocumentMouseMove", () => {
it("should call getCubeIntersectedByMouse", () => {
viewCubeMouseEventsService["getCubeIntersectedByMouse"] = jest.fn()
Expand Down Expand Up @@ -211,4 +290,25 @@ describe("ViewCubeMouseEventsService", () => {
expect(viewCubeMouseEventsService["triggerViewCubeClickEvent"]).toHaveBeenCalledWith(mockedCube)
})
})

describe("triggerViewCubeHoverEvent", () => {
it("should change cursor indicator", () => {
const cube = new Mesh()
viewCubeMouseEventsService["triggerViewCubeHoverEvent"](cube)
viewCubeMouseEventsService["$rootScope"].$broadcast = jest.fn()

expect(viewCubeMouseEventsService["currentlyHovered"]).toEqual(cube)
expect(document.body.style.cursor).toEqual(CursorType.Pointer)
})
})

describe("triggerViewCubeUnhoverEvent", () => {
it("should change cursor indicator", () => {
viewCubeMouseEventsService["triggerViewCubeUnhoverEvent"]()
viewCubeMouseEventsService["$rootScope"].$broadcast = jest.fn()

expect(viewCubeMouseEventsService["currentlyHovered"]).toEqual(null)
expect(document.body.style.cursor).toEqual(CursorType.Default)
})
})
})

0 comments on commit e2d1277

Please sign in to comment.