### Purpose Identicon generation is supposed to consider the first 15 characters of a device ID, e.g. if the ID is `ABCDEFG-HIJKLMN-...`, the identicon should be based on `ABCDEFGHIJKLMN`. However, the current implementation only strips the first dash, resulting in `ABCDEFGHIJKLM-`, so the last character is essentially fixed for all IDs. This corresponds to the lower-middle pixel in identicons always being "off" (see screenshots below). The fix is simple: Just add the `g` flag to the regex used to strip dashes. ### Screenshots Old vs. new, light theme: <img width="130" height="55" alt="light-old" src="https://github.com/user-attachments/assets/7aaf5a2d-bc8e-4fd9-af94-2e8d723e5369" /> <img width="130" height="55" alt="light-new" src="https://github.com/user-attachments/assets/b91a789b-5dbc-4d46-99e0-84d89f634e1f" /> Old vs. new, dark theme: <img width="130" height="55" alt="dark-old" src="https://github.com/user-attachments/assets/c3de5d4b-83d6-41fa-98da-18dd720462d3" /> <img width="130" height="55" alt="dark-new" src="https://github.com/user-attachments/assets/4d49f563-0ee6-40df-bae4-89149abf9e7e" /> Old vs. new, black theme: <img width="130" height="55" alt="black-old" src="https://github.com/user-attachments/assets/4c2e75a9-e658-4bdf-b9cc-e3dbc375cde3" /> <img width="130" height="55" alt="black-new" src="https://github.com/user-attachments/assets/c321c3d7-7bbb-433f-b750-2a688956ea40" /> Only ~50% of identicons will be affected, since it's based on the parity of the 15th character.
65 lines
2.1 KiB
JavaScript
65 lines
2.1 KiB
JavaScript
angular.module('syncthing.core')
|
|
.directive('identicon', ['$window', function ($window) {
|
|
var svgNS = 'http://www.w3.org/2000/svg';
|
|
|
|
function Identicon(value, size) {
|
|
var svg = document.createElementNS(svgNS, 'svg');
|
|
var shouldFillRectAt = function (row, col) {
|
|
return !($window.parseInt(value.charCodeAt(row + col * size), 10) % 2);
|
|
};
|
|
var shouldMirrorRectAt = function (row, col) {
|
|
return !(size % 2 && col === middleCol)
|
|
};
|
|
var mirrorColFor = function (col) {
|
|
return size - col - 1;
|
|
};
|
|
var fillRectAt = function (row, col) {
|
|
var rect = document.createElementNS(svgNS, 'rect');
|
|
|
|
rect.setAttribute('x', (col * rectSize) + '%');
|
|
rect.setAttribute('y', (row * rectSize) + '%');
|
|
rect.setAttribute('width', rectSize + '%');
|
|
rect.setAttribute('height', rectSize + '%');
|
|
|
|
svg.appendChild(rect);
|
|
};
|
|
var row;
|
|
var col;
|
|
var middleCol;
|
|
var rectSize;
|
|
|
|
svg.setAttribute('class', 'identicon');
|
|
size = size || 5;
|
|
rectSize = 100 / size;
|
|
middleCol = Math.ceil(size / 2) - 1;
|
|
|
|
if (value) {
|
|
value = value.toString().replace(/[\W_]/g, '');
|
|
|
|
for (row = 0; row < size; ++row) {
|
|
for (col = middleCol; col > -1; --col) {
|
|
if (shouldFillRectAt(row, col)) {
|
|
fillRectAt(row, col);
|
|
|
|
if (shouldMirrorRectAt(row, col)) {
|
|
fillRectAt(row, mirrorColFor(col));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return svg;
|
|
}
|
|
|
|
return {
|
|
restrict: 'E',
|
|
scope: {
|
|
value: '='
|
|
},
|
|
link: function (scope, element, attributes) {
|
|
element.append(new Identicon(scope.value));
|
|
}
|
|
}
|
|
}]);
|