From bfb80775a6fd6f89cbdd67e982cbd21e35eed974 Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Thu, 20 Oct 2022 13:57:28 +0000 Subject: [PATCH] Improve rects view code health Fix: b/254244305 Test: npm run test:component Change-Id: Iac424696b4351dc22c2f802d19aff6d7b029556c --- .../components/rects/canvas_graphics.ts | 271 +++++++++--------- 1 file changed, 132 insertions(+), 139 deletions(-) diff --git a/tools/winscope-ng/src/viewers/components/rects/canvas_graphics.ts b/tools/winscope-ng/src/viewers/components/rects/canvas_graphics.ts index 14dd36a84..a51827552 100644 --- a/tools/winscope-ng/src/viewers/components/rects/canvas_graphics.ts +++ b/tools/winscope-ng/src/viewers/components/rects/canvas_graphics.ts @@ -76,10 +76,7 @@ export class CanvasGraphics { } // set various factors for shading and shifting - const visibleDarkFactor = 0, nonVisibleDarkFactor = 0, rectCounter = 0; const numberOfRects = this.rects.length; - const numberOfVisibleRects = this.rects.filter(rect => rect.isVisible).length; - const numberOfNonVisibleRects = this.rects.filter(rect => !rect.isVisible).length; const zShift = numberOfRects * this.layerSeparation; let xShift = 0, yShift = 3.5, labelYShift = 0; @@ -105,12 +102,6 @@ export class CanvasGraphics { })) - labelYShift; this.drawScene( - rectCounter, - numberOfVisibleRects, - visibleDarkFactor, - numberOfNonVisibleRects, - nonVisibleDarkFactor, - numberOfRects, xShift, yShift, zShift, @@ -244,12 +235,6 @@ export class CanvasGraphics { } private drawScene( - rectCounter: number, - numberOfVisibleRects: number, - visibleDarkFactor: number, - numberOfNonVisibleRects: number, - nonVisibleDarkFactor: number, - numberOfRects: number, xShift: number, yShift: number, zShift: number, @@ -257,131 +242,101 @@ export class CanvasGraphics { ) { this.targetObjects = []; this.clearLabelElements(); - this.rects.forEach(rect => { + + const darkFactors = this.computeRectDarkFactors(this.rects); + + for (const [rectIndex, rect] of this.rects.entries()) { const mustNotDrawInVisibleView = this.visibleView && !rect.isVisible; const mustNotDrawInXrayViewWithoutVirtualDisplays = !this.visibleView && !this.showVirtualDisplays && rect.isVirtual; if (mustNotDrawInVisibleView || mustNotDrawInXrayViewWithoutVirtualDisplays) { - rectCounter++; return; } - //set colour mapping - let planeColor; - if (this.highlightedItems.includes(`${rect.id}`)) { - planeColor = this.colorMapping("highlighted", numberOfRects, 0); - } else if (rect.isVisible) { - planeColor = this.colorMapping("green", numberOfVisibleRects, visibleDarkFactor); - visibleDarkFactor++; - } else { - planeColor = this.colorMapping("grey", numberOfNonVisibleRects, nonVisibleDarkFactor); - nonVisibleDarkFactor++; - } + const darkFactor = darkFactors[rectIndex]; + const rectGeometry = new THREE.PlaneGeometry(rect.width, rect.height); + const rectMesh = this.makeRectMesh(rect, rectGeometry, xShift, yShift, zShift, darkFactor); + this.scene?.add(rectMesh); - //set plane geometry and material - const geometry = new THREE.PlaneGeometry(rect.width, rect.height); - const planeRect = this.setPlaneMaterial(rect, geometry, planeColor, xShift, yShift, zShift); - this.scene?.add(planeRect); - zShift -= this.layerSeparation; - - // bolder edges of each plane if in x-ray view + // rect with bolder edges in x-ray view if (!this.visibleView) { - const edgeSegments = this.setEdgeMaterial(planeRect, geometry); - this.scene?.add(edgeSegments); + const rectEdges = this.makeRectLineSegments(rectMesh, rectGeometry); + this.scene?.add(rectEdges); } - // only some rects are clickable if (rect.isClickable) { - this.targetObjects.push(planeRect); + this.targetObjects.push(rectMesh); } - // labelling elements - if (rect.label.length > 0) { - const circle = this.setCircleMaterial(planeRect, rect); - this.scene?.add(circle); - const [line, rectLabel] = this.createLabel(rect, circle, lowestY, rectCounter); - this.scene?.add(line); - this.scene?.add(rectLabel); - } + this.drawLabel(rect, rectMesh, lowestY, rectIndex); - rectCounter++; + zShift -= this.layerSeparation; + } + } + + private computeRectDarkFactors(rects: Rectangle[]): number[] { + let visibleRectsSoFar = 0; + const visibleRectsTotal = rects.reduce((count, rect) => { + return rect.isVisible ? count + 1 : count; + }, 0); + + let nonVisibleRectsSoFar = 0; + const nonVisibleRectsTotal = rects.reduce((count, rect) => { + return rect.isVisible ? count : count + 1; + }, 0); + + const factors = rects.map(rect => { + if (rect.isVisible) { + return (visibleRectsTotal - visibleRectsSoFar++) / visibleRectsTotal; + } else { + return (nonVisibleRectsTotal - nonVisibleRectsSoFar++) / nonVisibleRectsTotal; + } }); + + return factors; } - private setPlaneMaterial( - rect: Rectangle, - geometry: THREE.PlaneGeometry, - color: THREE.Color, - xShift: number, - yShift: number, - zShift: number - ) { - const planeRect = new THREE.Mesh( - geometry, - new THREE.MeshBasicMaterial({ - color: color, - opacity: this.visibleView ? 1 : 0.75, - transparent: true, - })); - planeRect.position.y = rect.topLeft.y - rect.height / 2 + yShift; - planeRect.position.x = rect.topLeft.x + rect.width / 2 - xShift; - planeRect.position.z = zShift; - planeRect.name = `${rect.id}`; - return planeRect; - } + private drawLabel(rect: Rectangle, rectMesh: THREE.Mesh, lowestY: number, rectCounter: number) { + if (rect.label.length == 0) { + return; + } - private setEdgeMaterial(planeRect: THREE.Mesh, geometry: THREE.PlaneGeometry) { - const edgeColor = 0x000000; - const edgeGeo = new THREE.EdgesGeometry(geometry); - const edgeMaterial = new THREE.LineBasicMaterial({ color: edgeColor, linewidth: 1 }); - const edgeSegments = new THREE.LineSegments( - edgeGeo, edgeMaterial - ); - edgeSegments.position.set(planeRect.position.x, planeRect.position.y, planeRect.position.z); - return edgeSegments; - } + const circleMesh = this.makeLabelCircleMesh(rectMesh, rect); + this.scene?.add(circleMesh); - private setCircleMaterial(planeRect: THREE.Mesh, rect: Rectangle) { - const labelCircle = new THREE.CircleGeometry(0.02, 200); - const circleMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 }); - const circle = new THREE.Mesh(labelCircle, circleMaterial); - circle.position.set( - planeRect.position.x + rect.width / 2 - 0.05, - planeRect.position.y, - planeRect.position.z + 0.05 - ); - circle.rotateY(THREE.MathUtils.degToRad(30)); - return circle; - } - - private createLabel(rect: Rectangle, circle: THREE.Mesh, lowestY: number, rectCounter: number): - [THREE.Line, CSS2DObject] { - const labelText = this.shortenText(rect.label); const isGrey = !this.visibleView && !rect.isVisible; - let endPos; + + let lineEndPos; const labelYSeparation = 0.5; if (this.isLandscape) { - endPos = new THREE.Vector3( - circle.position.x, lowestY - 0.5 - rectCounter * labelYSeparation, circle.position.z + lineEndPos = new THREE.Vector3( + circleMesh.position.x, lowestY - 0.5 - rectCounter * labelYSeparation, circleMesh.position.z ); } else { - endPos = new THREE.Vector3( - circle.position.x, lowestY + 0.5 - rectCounter * labelYSeparation, circle.position.z + lineEndPos = new THREE.Vector3( + circleMesh.position.x, lowestY + 0.5 - rectCounter * labelYSeparation, circleMesh.position.z ); } - const linePoints = [circle.position, endPos]; + const linePoints = [circleMesh.position, lineEndPos]; + const lineGeo = new THREE.BufferGeometry().setFromPoints(linePoints); + const lineMaterial = new THREE.LineBasicMaterial({ color: isGrey ? 0x808080 : 0x000000 }); + const line = new THREE.Line(lineGeo, lineMaterial); + this.scene?.add(line); + this.drawLabelTextHtml(lineEndPos, rect, isGrey); + } - //add rectangle label + private drawLabelTextHtml(position: THREE.Vector3, rect: Rectangle, isGrey: boolean) { + // Add rectangle label const spanText: HTMLElement = document.createElement("span"); - spanText.innerText = labelText; + spanText.innerText = this.shortenText(rect.label); spanText.className = "mat-body-1"; - // Hack: transparent/placeholder text used to push the visible text to the left (negative x) - // and properly align it with the label's line + // Hack: transparent/placeholder text used to push the visible text towards left + // (towards negative x) and properly align it with the label's vertical segment const spanPlaceholder: HTMLElement = document.createElement("span"); - spanPlaceholder.innerText = labelText; + spanPlaceholder.innerText = this.shortenText(rect.label); spanPlaceholder.className = "mat-body-1"; spanPlaceholder.style.opacity = "0"; @@ -401,20 +356,80 @@ export class CanvasGraphics { "click", (event) => this.propagateUpdateHighlightedItems(event, rect.id) ); - const rectLabel = new CSS2DObject(div); - rectLabel.name = rect.label; - - rectLabel.position.set( - endPos.x, - endPos.y, - endPos.z + const label = new CSS2DObject(div); + label.name = rect.label; + label.position.set( + position.x, + position.y, + position.z ); - const lineGeo = new THREE.BufferGeometry().setFromPoints(linePoints); - const lineMaterial = new THREE.LineBasicMaterial({ color: isGrey ? 0x808080 : 0x000000 }); - const line = new THREE.Line(lineGeo, lineMaterial); + this.scene?.add(label); + } - return [line, rectLabel]; + private makeRectMesh( + rect: Rectangle, + geometry: THREE.PlaneGeometry, + xShift: number, + yShift: number, + zShift: number, + darkFactor: number, + ): THREE.Mesh { + let color: THREE.Color; + + if (this.highlightedItems.includes(`${rect.id}`)) { + color = new THREE.Color(0xD2E3FC); + } else if (rect.isVisible) { + // green (darkness depends on z order) + const red = ((200 - 45) * darkFactor + 45) / 255; + const green = ((232 - 182) * darkFactor + 182) / 255; + const blue = ((183 - 44) * darkFactor + 44) / 255; + color = new THREE.Color(red, green, blue); + } else { + // grey (darkness depends on z order) + const lower = 120; + const upper = 220; + const darkness = ((upper - lower) * darkFactor + lower) / 255; + color = new THREE.Color(darkness, darkness, darkness); + } + + const mesh = new THREE.Mesh( + geometry, + new THREE.MeshBasicMaterial({ + color: color, + opacity: this.visibleView ? 1 : 0.75, + transparent: true, + })); + mesh.position.y = rect.topLeft.y - rect.height / 2 + yShift; + mesh.position.x = rect.topLeft.x + rect.width / 2 - xShift; + mesh.position.z = zShift; + mesh.name = `${rect.id}`; + + return mesh; + } + + private makeRectLineSegments(rectMesh: THREE.Mesh, geometry: THREE.PlaneGeometry): THREE.LineSegments { + const edgeColor = 0x000000; + const edgeGeo = new THREE.EdgesGeometry(geometry); + const edgeMaterial = new THREE.LineBasicMaterial({ color: edgeColor, linewidth: 1 }); + const edgeSegments = new THREE.LineSegments( + edgeGeo, edgeMaterial + ); + edgeSegments.position.set(rectMesh.position.x, rectMesh.position.y, rectMesh.position.z); + return edgeSegments; + } + + private makeLabelCircleMesh(rectMesh: THREE.Mesh, rect: Rectangle): THREE.Mesh { + const geometry = new THREE.CircleGeometry(0.02, 200); + const material = new THREE.MeshBasicMaterial({ color: 0x000000 }); + const mesh = new THREE.Mesh(geometry, material); + mesh.position.set( + rectMesh.position.x + rect.width / 2 - 0.05, + rectMesh.position.y, + rectMesh.position.z + 0.05 + ); + mesh.rotateY(THREE.MathUtils.degToRad(30)); + return mesh; } private propagateUpdateHighlightedItems(event: MouseEvent, newId: number) { @@ -438,28 +453,6 @@ export class CanvasGraphics { document.querySelectorAll(".rect-label").forEach(el => el.remove()); } - private colorMapping(scale: string, numberOfRects: number, darkFactor: number): THREE.Color { - if (scale === "highlighted") { - return new THREE.Color(0xD2E3FC); - } else if (scale === "grey") { - // darkness of grey rect depends on z order - darkest 64, lightest 128 - //Separate RGB values between 0 and 1 - const lower = 120; - const upper = 220; - const darkness = ((upper - lower) * (numberOfRects - darkFactor) / numberOfRects + lower) / 255; - return new THREE.Color(darkness, darkness, darkness); - } else if (scale === "green") { - // darkness of green rect depends on z order - //Separate RGB values between 0 and 1 - const red = ((200 - 45) * (numberOfRects - darkFactor) / numberOfRects + 45) / 255; - const green = ((232 - 182) * (numberOfRects - darkFactor) / numberOfRects + 182) / 255; - const blue = ((183 - 44) * (numberOfRects - darkFactor) / numberOfRects + 44) / 255; - return new THREE.Color(red, green, blue); - } else { - return new THREE.Color(0, 0, 0); - } - } - private shortenText(text: string): string { if (text.length > 35) { text = text.slice(0, 35);