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

Bug/3044/margin renders some buildings missing #3077

Merged
merged 47 commits into from
Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
98cf5b8
Fix margin issue, based on prev discussed algorithm, change margin fa…
RomanenkoVladimir Sep 28, 2022
edd2773
Merge branch 'main' into bug/3044/margin-renders-some-buildings-missing
RomanenkoVladimir Sep 28, 2022
092c2f8
Rename helperFile, fix error in median calculation, add paddingCalcul…
RomanenkoVladimir Sep 28, 2022
b73e327
Add tests for new helper functions
RomanenkoVladimir Sep 28, 2022
f03ca0e
Fix calculation of folder labels removing buildings
RomanenkoVladimir Sep 29, 2022
aeaa6ef
Change minBuildingArea back to 100
RomanenkoVladimir Sep 29, 2022
4c0e669
Add tests for nodeAreaCalculator, fix some issues with floating point…
RomanenkoVladimir Sep 29, 2022
7da97ab
Update tests and algo
RomanenkoVladimir Oct 6, 2022
fc27831
Merge branch 'main' into bug/3044/margin-renders-some-buildings-missing
RomanenkoVladimir Oct 6, 2022
bfcd225
Apply feedback
RomanenkoVladimir Oct 7, 2022
724ac33
Merge branch 'main' into bug/3044/margin-renders-some-buildings-missing
RomanenkoVladimir Oct 7, 2022
9e51f0b
Fix lexicographic sort
RomanenkoVladimir Oct 7, 2022
1e29a9f
Merge branch 'bug/3044/margin-renders-some-buildings-missing' of gith…
RomanenkoVladimir Oct 7, 2022
481a16a
Fix lexicographic sort test
RomanenkoVladimir Oct 7, 2022
51f32c9
Fix lexicographic sort
RomanenkoVladimir Oct 7, 2022
baed035
Update algo for clearness, fix small bug
RomanenkoVladimir Oct 18, 2022
1a827cb
Update algorithm to correctly display width and height, add documenat…
RomanenkoVladimir Oct 19, 2022
6ea141a
Change calculation to square, add paddings, change calculation to con…
RomanenkoVladimir Oct 21, 2022
e1765ad
Merge branch 'main' into bug/3044/margin-renders-some-buildings-missing
RomanenkoVladimir Oct 21, 2022
a99edd1
Refactor some constants
RomanenkoVladimir Oct 21, 2022
2d4dcd2
Fix arrows failing to draw for unrendered buildings (e.g. buuilding a…
RomanenkoVladimir Oct 24, 2022
520623b
Change padding applciation, now all buildings should always be visibl…
RomanenkoVladimir Oct 24, 2022
1d900c3
Merge branch 'main' into bug/3044/margin-renders-some-buildings-missing
RomanenkoVladimir Oct 31, 2022
feb4c78
Update nodeAreaCalculator to throw an error when area is 0 for all bu…
RomanenkoVladimir Oct 31, 2022
f53dbd1
Update documentation
RomanenkoVladimir Oct 31, 2022
98b2465
Fix overlapping floor label texts
RomanenkoVladimir Nov 2, 2022
d5df7e6
Change Map scaling to be factor based, Add corresponding test
RomanenkoVladimir Nov 3, 2022
6c13d0b
Remove invert area button for now
RomanenkoVladimir Nov 4, 2022
8222006
Apply padding to buildings, lost in prev commit
RomanenkoVladimir Nov 4, 2022
1fac75f
Change margin to %
RomanenkoVladimir Nov 4, 2022
6b3f2e6
Merge branch 'main' into bug/3044/margin-renders-some-buildings-missing
RomanenkoVladimir Nov 4, 2022
5a193b3
add 0.001 additional folder area to reduce risk of elimintation, chan…
RomanenkoVladimir Nov 4, 2022
08d98d6
Change folder label area calculation from estimate to almost precise,…
RomanenkoVladimir Nov 4, 2022
dd6c266
Update docs with floor label calculation change
RomanenkoVladimir Nov 4, 2022
84e6f06
Merge branch 'main' into bug/3044/margin-renders-some-buildings-missing
RomanenkoVladimir Nov 4, 2022
5ac1c89
Merge branch 'bug/3044/margin-renders-some-buildings-missing' of gith…
RomanenkoVladimir Nov 4, 2022
360ce58
Remove map resoultion factor from floor labels and treeMap, scale bui…
RomanenkoVladimir Nov 4, 2022
0c51055
Revert "Remove map resoultion factor from floor labels and treeMap, s…
RomanenkoVladimir Nov 4, 2022
80d4f1f
Rollback change to mapResolutionScaling as it breaks Firefox, make fl…
RomanenkoVladimir Nov 4, 2022
8171d4c
Update docs
RomanenkoVladimir Nov 4, 2022
00ead58
Merge branch 'main' into bug/3044/margin-renders-some-buildings-missing
RomanenkoVladimir Nov 17, 2022
ab9b744
Fix eslint compliance
RomanenkoVladimir Nov 17, 2022
0677616
Merge branch 'main' into bug/3044/margin-renders-some-buildings-missing
MW-Friedrich Nov 22, 2022
dacac65
chore: fix a few missed spelling errors
MW-Friedrich Nov 22, 2022
8a335d5
Merge branch 'main' into bug/3044/margin-renders-some-buildings-missing
MW-Friedrich Nov 22, 2022
7323f53
chore: fix formatting (Prettier)
MW-Friedrich Nov 22, 2022
699842b
chore: fix formatting (Prettier)
MW-Friedrich Nov 22, 2022
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/)

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

### Added 🚀

- New calculation algorithm for treeMap that accounts for paddings and floor labels [#3077](https://github.com/MaibornWolff/codecharta/pull/3077)

### Chore 👨‍💻 👩‍💻

- Documentation for new treeMap calcuation algorithm [#3077](https://github.com/MaibornWolff/codecharta/pull/3077)

## [1.110.0] - 2022-11-04

### Changed
Expand Down Expand Up @@ -59,6 +67,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/)
- Update Docker Publish Action in Release Pipeline [#3060](https://github.com/MaibornWolff/codecharta/pull/3060)
- Write documentation for docker containers [#3063](https://github.com/MaibornWolff/codecharta/pull/3063)
- Migrate isAttributeSideBarVisible.service, threeScene.service, threeCamera.service and threeStats.service to Angular [#3068](https://github.com/MaibornWolff/codecharta/pull/3068)
- Migrate dialog.service to Angular [#3072](https://github.com/MaibornWolff/codecharta/pull/3072)
- Add documentation for new treeMap algorithm [#3077](https://github.com/MaibornWolff/codecharta/pull/3077)
- Migrate dialog.service to Angular [#3070](https://github.com/MaibornWolff/codecharta/pull/3070)
- Migrate FocusedNodePathService, LayoutAlgorithmService, ThreeOrbitControlsService and ThreeViewerService to Angular [#3072](https://github.com/MaibornWolff/codecharta/pull/3072)
- Migrate updateAttributeTypes.service to Angular [#3082](https://github.com/MaibornWolff/codecharta/pull/3082)
Expand Down
2 changes: 2 additions & 0 deletions gh-pages/_data/navigation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ docs:
url: /docs/user-controls/
- title: "Timeline"
url: /docs/timeline/
- title: "Tree Map Hierarchy Algorithm"
url: /docs/tree-map-hierarchy/
- title: "Custom View"
url: /docs/custom-view/

Expand Down
43 changes: 43 additions & 0 deletions gh-pages/_docs/06-04-tree-map-hierarchy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---

permalink: /docs/tree-map-algorithm/
title: "Tree Map Algorithm"

The CodeCharta map is generated by calculating a map size first as well as placing all 2d buildings and folders as areas. Afterwards we use [three-js](https://threejs.org) to generate the 3d-models at the calculated positions.

In this document we will focus on the first part, the placement algorithm. We use [d3-hierarchy](https://github.com/d3/d3-hierarchy), a module for visualizing hierarchical data, like our code maps. The algorithm operates by placing buildings inside sub-folders and sub-folders inside their parents. All those steps ar performed in a depth-first manner all the way up to the root node.
BridgeAR marked this conversation as resolved.
Show resolved Hide resolved
To calculate an "optimal" packing the algorithm requires a hierarchical structure with node sizes and width and height of the root node. When receiving the data d3-hierarchy calculates a placement and allows applying margins to components.

For our visualization we apply outer-margins to have padding between folders and inner-margins for padding between the files in each folder. Furthermore, we use paddingRight to generate folder labels **below** each folder.

However, the problem with the approach is that margins are not part of the calculated map size, which leads to buildings being "compressed", e.g. a building of area 100 appearing smaller in area then a building of size 50. In some cases it even leads to buildings disappearing entirely.

The algorithm presented below aims to address the issue by calculating building areas extended by padding and providing them to the algorithm instead. This allows us to reserve more space even before paddings are applied by d3-hierarchy.

Open issues that remain are folder labels being scaled to the map size which would require two passes to address properly.

## Methods and Function

| Method | Function |
| :-----------------------------------------: | ---------------------------------------------------------------------- |
| `getChildrenAreaValues()` | returns all non zero area values for a given metric and hierarchy node |
| `getSmallestValueOrSmallestDifference()` | returns minimum between smallest difference and smallest value |
| `calculatePaddingBasedOnBuildingArea()` | calculate the median building area and scale padding down |
| `getBuildingAreasWithProportionalPadding()` | scale building area by minimum-area by delta, add scaled padding |
| `calculateTotalNodeArea()` | calculate map width, height and hierarchy via d3 |

## calculateTotalNodeArea: intermediate steps

| Steps | intermediate results |
| :---: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `1:` | **totalNodeArea**: sum building areas or throw an error if none exist |
| `2:` | generate two maps from hierarchyNode<br>**nodeKeyMap(path, node)**: maps paths to node data, helps find parent/child of node<br> **nodeAreaMap(path, 0)**: maps paths to a node area value, all set to 0 at start |
| `3:` | **nodeAreaMap**: set file values and folder values as sum of direct children only |
| `4:` | **paths** : reverse nodeKeyMap(), d3-hierarchy operates depth first |
| `5:` | **nodeAreaMap**: add children folder areas to parent folders, root now contains total area including innerPaddings |
| `6:` | calculate and apply scaling factor for each file-area per folder <br> count the amount of fodlers with floor label per hierarchy level |
| `7:` | hierarchyNode sum up each file in place for further calculations |
| `8:` | **totalNodeArea**: add paddings areas to sum of folder areas (outerPadding), add folder label sizes |
| `9:` | **rootSide**: set root side length<br> root-folder is always a square |
| `10:` | **factor**: check if map root is to big and set a factor to scale down if required |
| `11:` | **metricSum**: sum up all files again (overwrite), applying scaling factor to each file/folder if required |
1 change: 1 addition & 0 deletions visualization/app/codeCharta/codeCharta.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ export interface Node {
markingColor: string | void
flat: boolean
color: string
fitForFolderLabel: boolean | undefined
incomingEdgePoint: Vector3
outgoingEdgePoint: Vector3
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ export function setMargin(margin: number = defaultMargin): SetMarginAction {
}
}

export const defaultMargin = 50
export const defaultMargin = 100
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Array [
"outgoing": 666,
},
},
"fitForFolderLabel": false,
"flat": false,
"height": 2,
"heightDelta": 20,
Expand Down Expand Up @@ -102,6 +103,7 @@ Array [
"outgoing": 666,
},
},
"fitForFolderLabel": false,
"flat": false,
"height": 2,
"heightDelta": 20,
Expand Down Expand Up @@ -170,6 +172,7 @@ CodeMapBuilding {
"outgoing": 666,
},
},
"fitForFolderLabel": false,
"flat": false,
"height": 2,
"heightDelta": 20,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,30 @@ Array [
"deltas": undefined,
"depth": 0,
"edgeAttributes": Object {},
"fitForFolderLabel": false,
"flat": false,
"height": 2,
"heightDelta": 0,
"id": 0,
"incomingEdgePoint": Vector3 {
"x": 225.07550765359252,
"x": -73.5,
"y": 2,
"z": -12.462246173203738,
"z": -161.75,
},
"isLeaf": false,
"length": 950.151015307185,
"length": 353,
"link": undefined,
"mapNodeDepth": 0,
"markingColor": undefined,
"name": "root",
"outgoingEdgePoint": Vector3 {
"x": 225.07550765359252,
"x": -73.5,
"y": 2,
"z": 462.6132614803888,
"z": 14.75,
},
"path": "/root",
"visible": true,
"width": 950.151015307185,
"width": 353,
"x0": 0,
"y0": 0,
"z0": 0,
Expand All @@ -50,31 +51,32 @@ Array [
"deltas": undefined,
"depth": 1,
"edgeAttributes": Object {},
"fitForFolderLabel": false,
"flat": false,
"height": 2,
"heightDelta": 0,
"id": 1,
"incomingEdgePoint": Vector3 {
"x": -32.862246173203744,
"x": -191.1541519434629,
"y": 4,
"z": -2.862246173203772,
"z": -153.75,
},
"isLeaf": true,
"length": 911.751015307185,
"length": 321,
"link": "https://www.google.de",
"mapNodeDepth": 1,
"markingColor": undefined,
"name": "big leaf",
"outgoingEdgePoint": Vector3 {
"x": -32.862246173203744,
"x": -191.1541519434629,
"y": 4,
"z": 453.01326148038873,
"z": 6.75,
},
"path": "/root/big leaf",
"visible": true,
"width": 395.87550765359254,
"x0": 19.200000000000003,
"y0": 19.200000000000003,
"width": 85.6916961130742,
"x0": 16,
"y0": 16,
"z0": 2,
},
Object {
Expand All @@ -87,31 +89,32 @@ Array [
"deltas": undefined,
"depth": 1,
"edgeAttributes": Object {},
"fitForFolderLabel": true,
"flat": false,
"height": 2,
"heightDelta": 0,
"id": 2,
"incomingEdgePoint": Vector3 {
"x": 382.21326148038884,
"x": -64.65415194346289,
"y": 4,
"z": -2.862246173203772,
"z": -153.75,
},
"isLeaf": false,
"length": 911.751015307185,
"length": 321,
"link": undefined,
"mapNodeDepth": 1,
"markingColor": undefined,
"name": "Parent Leaf",
"outgoingEdgePoint": Vector3 {
"x": 382.21326148038884,
"x": -64.65415194346289,
"y": 4,
"z": 453.01326148038873,
"z": 6.75,
},
"path": "/root/Parent Leaf",
"visible": true,
"width": 395.8755076535925,
"x0": 434.27550765359257,
"y0": 19.200000000000003,
"width": 135.30830388692578,
"x0": 117.6916961130742,
"y0": 16,
"z0": 2,
},
Object {
Expand All @@ -125,31 +128,32 @@ Array [
"deltas": undefined,
"depth": 2,
"edgeAttributes": Object {},
"fitForFolderLabel": false,
"flat": false,
"height": 2,
"heightDelta": 0,
"id": 3,
"incomingEdgePoint": Vector3 {
"x": 273.8943845669907,
"x": -99.15415194346289,
"y": 6,
"z": -87.31734770392224,
"z": -199.13626292466765,
},
"isLeaf": true,
"length": 248.5653045921555,
"length": 75.4549483013294,
"link": undefined,
"mapNodeDepth": 2,
"markingColor": undefined,
"name": "small leaf",
"outgoingEdgePoint": Vector3 {
"x": 414.73213839378695,
"x": -99.15415194346289,
"y": 6,
"z": -87.31734770392224,
"z": -161.40878877400297,
},
"path": "/root/Parent Leaf/small leaf",
"visible": true,
"width": 281.67550765359243,
"x0": 453.4755076535926,
"y0": 38.400000000000006,
"width": 34.308303886925785,
"x0": 133.69169611307422,
"y0": 32,
"z0": 4,
},
Object {
Expand All @@ -163,31 +167,32 @@ Array [
"deltas": undefined,
"depth": 2,
"edgeAttributes": Object {},
"fitForFolderLabel": false,
"flat": false,
"height": 2,
"heightDelta": 0,
"id": 4,
"incomingEdgePoint": Vector3 {
"x": 344.31326148038886,
"x": -99.15415194346289,
"y": 6,
"z": 207.5617322709129,
"z": -77.15878877400296,
},
"isLeaf": true,
"length": 605.5857107150293,
"length": 197.5450516986706,
"link": undefined,
"mapNodeDepth": 2,
"markingColor": undefined,
"name": "other small leaf",
"outgoingEdgePoint": Vector3 {
"x": 344.31326148038886,
"x": -99.15415194346289,
"y": 6,
"z": 510.35458762842757,
"z": 21.613737075332338,
},
"path": "/root/Parent Leaf/other small leaf",
"visible": true,
"width": 281.67550765359243,
"x0": 453.4755076535926,
"y0": 306.16530459215556,
"width": 34.308303886925785,
"x0": 133.69169611307422,
"y0": 123.4549483013294,
"z0": 4,
},
Object {
Expand All @@ -200,14 +205,15 @@ Array [
"deltas": undefined,
"depth": 2,
"edgeAttributes": Object {},
"fitForFolderLabel": false,
"flat": false,
"height": 500,
"heightDelta": 0,
"id": 5,
"incomingEdgePoint": Vector3 {
"x": 273.8943845669907,
"x": -107.73122791519434,
"y": 504,
"z": 671.351015307185,
"z": 79,
},
"isLeaf": true,
"length": 0,
Expand All @@ -216,15 +222,15 @@ Array [
"markingColor": undefined,
"name": "empty folder",
"outgoingEdgePoint": Vector3 {
"x": 414.73213839378695,
"x": -90.57707597173145,
"y": 504,
"z": 671.351015307185,
"z": 79,
},
"path": "/root/Parent Leaf/empty folder",
"visible": true,
"width": 281.67550765359243,
"x0": 453.4755076535926,
"y0": 921.351015307185,
"width": 34.308303886925785,
"x0": 133.69169611307422,
"y0": 329,
"z0": 4,
},
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ describe("CodeMapArrowService", () => {
expect(codeMapArrowService["showEdgesOfBuildings"]).toHaveBeenCalledTimes(0)
expect(codeMapArrowService.addEdgePreview).toHaveBeenCalled()
})

it("should not call clearArrows and showEdgesOfBuildings when a building does not exist", () => {
codeMapArrowService.onBuildingSelected({ building: undefined })

expect(codeMapArrowService.clearArrows).not.toHaveBeenCalled()
expect(codeMapArrowService["showEdgesOfBuildings"]).not.toHaveBeenCalled()
expect(codeMapArrowService.addEdgePreview).not.toHaveBeenCalled()
})
})

describe("clearArrows", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export class CodeMapArrowService {
}

private isEdgeApplicableForBuilding(codeMapBuilding: CodeMapBuilding) {
return this.state.getValue().appSettings.isEdgeMetricVisible && !codeMapBuilding.node.flat
return this.state.getValue().appSettings.isEdgeMetricVisible && codeMapBuilding && !codeMapBuilding.node.flat
}

private showEdgesOfBuildings(hoveredbuilding?: CodeMapBuilding) {
Expand Down