Skip to content

Commit

Permalink
stable color rendering (#501)
Browse files Browse the repository at this point in the history
* stable color rendering

* fix case sensitivity

* rename variables

* Decrease color saturation

* Update changelog

* Add missing newline

Co-authored-by: Vesa Laakso <482561+valscion@users.noreply.github.com>
  • Loading branch information
CreativeTechGuy and valscion committed Aug 19, 2022
1 parent 16d8e07 commit 3ce0d21
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -14,6 +14,7 @@ _Note: Gaps between patch versions are faulty, broken or test releases._

* **New Feature**
* Support outputting different URL in server mode ([#520](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/520) by [@southorange1228](https://github.com/southorange1228))
* Use deterministic chunk colors (#[501](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/501) by [@CreativeTechGuy](https://github.com/CreativeTechGuy))

## 4.5.0

Expand Down
76 changes: 76 additions & 0 deletions client/components/Treemap.jsx
Expand Up @@ -7,6 +7,7 @@ export default class Treemap extends Component {
super(props);
this.treemap = null;
this.zoomOutDisabled = false;
this.findChunkNamePartIndex();
}

componentDidMount() {
Expand All @@ -16,6 +17,7 @@ export default class Treemap extends Component {

componentWillReceiveProps(nextProps) {
if (nextProps.data !== this.props.data) {
this.findChunkNamePartIndex();
this.treemap.set({
dataObject: this.getTreemapDataObject(nextProps.data)
});
Expand Down Expand Up @@ -76,6 +78,19 @@ export default class Treemap extends Component {
vars.titleBarShown = false;
},
groupColorDecorator(options, properties, variables) {
const root = component.getGroupRoot(properties.group);
const chunkName = component.getChunkNamePart(root.label);
const hash = /[^0-9]/u.test(chunkName)
? hashCode(chunkName)
: (parseInt(chunkName) / 1000) * 360;
variables.groupColor = {
model: 'hsla',
h: Math.round(Math.abs(hash) % 360),
s: 60,
l: 50,
a: 0.9
};

const {highlightGroups} = component.props;
const module = properties.group;

Expand Down Expand Up @@ -136,6 +151,14 @@ export default class Treemap extends Component {
});
}

getGroupRoot(group) {
let nextParent;
while (!group.isAsset && (nextParent = this.treemap.get('hierarchy', group).parent)) {
group = nextParent;
}
return group;
}

zoomToGroup(group) {
this.zoomOutDisabled = false;

Expand Down Expand Up @@ -164,9 +187,62 @@ export default class Treemap extends Component {
if (props.onResize) {
props.onResize();
}
};

/**
* Finds patterns across all chunk names to identify the unique "name" part.
*/
findChunkNamePartIndex() {
const splitChunkNames = this.props.data.map((chunk) => chunk.label.split(/[^a-z0-9]/iu));
const longestSplitName = Math.max(...splitChunkNames.map((parts) => parts.length));
const namePart = {
index: 0,
votes: 0
};
for (let i = longestSplitName - 1; i >= 0; i--) {
const identifierVotes = {
name: 0,
hash: 0,
ext: 0
};
let lastChunkPart = '';
for (const splitChunkName of splitChunkNames) {
const part = splitChunkName[i];
if (part === undefined || part === '') {
continue;
}
if (part === lastChunkPart) {
identifierVotes.ext++;
} else if (/[a-z]/u.test(part) && /[0-9]/u.test(part) && part.length === lastChunkPart.length) {
identifierVotes.hash++;
} else if (/^[a-z]+$/iu.test(part) || /^[0-9]+$/u.test(part)) {
identifierVotes.name++;
}
lastChunkPart = part;
}
if (identifierVotes.name >= namePart.votes) {
namePart.index = i;
namePart.votes = identifierVotes.name;
}
}
this.chunkNamePartIndex = namePart.index;
}

getChunkNamePart(chunkLabel) {
return chunkLabel.split(/[^a-z0-9]/iu)[this.chunkNamePartIndex] || chunkLabel;
}
}

function preventDefault(event) {
event.preventDefault();
}

function hashCode(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const code = str.charCodeAt(i);
hash = (hash << 5) - hash + code;
hash = hash & hash;
}
return hash;
}

0 comments on commit 3ce0d21

Please sign in to comment.