This repository has been archived by the owner on Sep 11, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 827
Make SVGs and CSS dynamically recolourable #77
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
4f915d6
switch SVGs from imgs to objects
ara4n 3009da0
move title attributes to the div
ara4n 555abda
wire up Tinter.js
ara4n 001dc86
support fixing up dynamically loaded SVGs
ara4n 0e98764
oops, no double classNames
ara4n 9cf49eb
oops, forgot this
ara4n aa1012b
oops
ara4n 9e8daba
Merge branch 'develop' into matthew/dynamic-svg
ara4n 509ea7c
factor out tintable SVGs into their own component, and use plain DOM …
ara4n 44a0fa1
comment /tint
ara4n f499c60
sundry PR feedback
ara4n 8c1bb90
add fixme
ara4n 0f52c0a
make TintableSvgs responsible for updating their own tints, and stop …
ara4n 296b626
oops, we actually need to cache the fixups in TintableSvg
ara4n fd32362
oops, initialise fixups per-object, not per-prototype
ara4n File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
/* | ||
Copyright 2015 OpenMarket Ltd | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
var dis = require("./dispatcher"); | ||
|
||
// FIXME: these vars should be bundled up and attached to | ||
// module.exports otherwise this will break when included by both | ||
// react-sdk and apps layered on top. | ||
|
||
// The colour keys to be replaced as referred to in SVGs | ||
var keyRgb = [ | ||
"rgb(118, 207, 166)", // Vector Green | ||
"rgb(234, 245, 240)", // Vector Light Green | ||
"rgba(118, 207, 166, 0.2)", // BottomLeftMenu overlay (20% Vector Green) | ||
]; | ||
|
||
// Some algebra workings for calculating the tint % of Vector Green & Light Green | ||
// x * 118 + (1 - x) * 255 = 234 | ||
// x * 118 + 255 - 255 * x = 234 | ||
// x * 118 - x * 255 = 234 - 255 | ||
// (255 - 118) x = 255 - 234 | ||
// x = (255 - 234) / (255 - 118) = 0.16 | ||
|
||
// The colour keys to be replaced as referred to in SVGs | ||
var keyHex = [ | ||
"#76CFA6", // Vector Green | ||
"#EAF5F0", // Vector Light Green | ||
"#D3EFE1", // BottomLeftMenu overlay (20% Vector Green overlaid on Vector Light Green) | ||
]; | ||
|
||
// cache of our replacement colours | ||
// defaults to our keys. | ||
var colors = [ | ||
keyHex[0], | ||
keyHex[1], | ||
keyHex[2], | ||
]; | ||
|
||
var cssFixups = [ | ||
// { | ||
// style: a style object that should be fixed up taken from a stylesheet | ||
// attr: name of the attribute to be clobbered, e.g. 'color' | ||
// index: ordinal of primary, secondary or tertiary | ||
// } | ||
]; | ||
|
||
// CSS attributes to be fixed up | ||
var cssAttrs = [ | ||
"color", | ||
"backgroundColor", | ||
"borderColor", | ||
]; | ||
|
||
var svgAttrs = [ | ||
"fill", | ||
"stroke", | ||
]; | ||
|
||
var cached = false; | ||
|
||
function calcCssFixups() { | ||
for (var i = 0; i < document.styleSheets.length; i++) { | ||
var ss = document.styleSheets[i]; | ||
for (var j = 0; j < ss.cssRules.length; j++) { | ||
var rule = ss.cssRules[j]; | ||
if (!rule.style) continue; | ||
for (var k = 0; k < cssAttrs.length; k++) { | ||
var attr = cssAttrs[k]; | ||
for (var l = 0; l < keyRgb.length; l++) { | ||
if (rule.style[attr] === keyRgb[l]) { | ||
cssFixups.push({ | ||
style: rule.style, | ||
attr: attr, | ||
index: l, | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
function applyCssFixups() { | ||
for (var i = 0; i < cssFixups.length; i++) { | ||
var cssFixup = cssFixups[i]; | ||
cssFixup.style[cssFixup.attr] = colors[cssFixup.index]; | ||
} | ||
} | ||
|
||
function hexToRgb(color) { | ||
if (color[0] === '#') color = color.slice(1); | ||
if (color.length === 3) { | ||
color = color[0] + color[0] + | ||
color[1] + color[1] + | ||
color[2] + color[2]; | ||
} | ||
var val = parseInt(color, 16); | ||
var r = (val >> 16) & 255; | ||
var g = (val >> 8) & 255; | ||
var b = val & 255; | ||
return [r, g, b]; | ||
} | ||
|
||
function rgbToHex(rgb) { | ||
var val = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]; | ||
return '#' + (0x1000000 + val).toString(16).slice(1) | ||
} | ||
|
||
module.exports = { | ||
tint: function(primaryColor, secondaryColor, tertiaryColor) { | ||
if (!cached) { | ||
calcCssFixups(); | ||
cached = true; | ||
} | ||
|
||
if (!secondaryColor) { | ||
var x = 0.16; // average weighting factor calculated from vector green & light green | ||
var rgb = hexToRgb(primaryColor); | ||
rgb[0] = x * rgb[0] + (1 - x) * 255; | ||
rgb[1] = x * rgb[1] + (1 - x) * 255; | ||
rgb[2] = x * rgb[2] + (1 - x) * 255; | ||
secondaryColor = rgbToHex(rgb); | ||
} | ||
|
||
if (!tertiaryColor) { | ||
var x = 0.19; | ||
var rgb1 = hexToRgb(primaryColor); | ||
var rgb2 = hexToRgb(secondaryColor); | ||
rgb1[0] = x * rgb1[0] + (1 - x) * rgb2[0]; | ||
rgb1[1] = x * rgb1[1] + (1 - x) * rgb2[1]; | ||
rgb1[2] = x * rgb1[2] + (1 - x) * rgb2[2]; | ||
tertiaryColor = rgbToHex(rgb1); | ||
} | ||
|
||
colors = [primaryColor, secondaryColor, tertiaryColor]; | ||
|
||
// go through manually fixing up the stylesheets. | ||
applyCssFixups(); | ||
|
||
// tell all the SVGs to go fix themselves up | ||
dis.dispatch({ action: 'tint_update' }); | ||
}, | ||
|
||
// XXX: we could just move this all into TintableSvg, but as it's so similar | ||
// to the CSS fixup stuff in Tinter (just that the fixups are stored in TintableSvg) | ||
// keeping it here for now. | ||
calcSvgFixups: function(svgs) { | ||
// go through manually fixing up SVG colours. | ||
// we could do this by stylesheets, but keeping the stylesheets | ||
// updated would be a PITA, so just brute-force search for the | ||
// key colour; cache the element and apply. | ||
|
||
var fixups = []; | ||
for (var i = 0; i < svgs.length; i++) { | ||
var svgDoc = svgs[i].contentDocument; | ||
if (!svgDoc) continue; | ||
var tags = svgDoc.getElementsByTagName("*"); | ||
for (var j = 0; j < tags.length; j++) { | ||
var tag = tags[j]; | ||
for (var k = 0; k < svgAttrs.length; k++) { | ||
var attr = svgAttrs[k]; | ||
for (var l = 0; l < keyHex.length; l++) { | ||
if (tag.getAttribute(attr) && tag.getAttribute(attr).toUpperCase() === keyHex[l]) { | ||
fixups.push({ | ||
node: tag, | ||
attr: attr, | ||
index: l, | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return fixups; | ||
}, | ||
|
||
applySvgFixups: function(fixups) { | ||
for (var i = 0; i < fixups.length; i++) { | ||
var svgFixup = fixups[i]; | ||
svgFixup.node.setAttribute(svgFixup.attr, colors[svgFixup.index]); | ||
} | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(most of) the other commands have a comment saying what they do. wouldn't hurt here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done