Last active
August 31, 2018 05:59
-
-
Save uglow/3376b0d0dfc207d06c1cc1d625de95d8 to your computer and use it in GitHub Desktop.
DrawIO SVG Filter Button script
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
//<![CDATA[ | |
// This script is designed to be imported by an SVG file created by DrawIO. | |
// While we wait for DrawIO to export layers and groups correctly for SVGs, | |
// this is a hacky way to add filter buttons to filter shapes based on their stroke or fill. | |
// | |
// It basically works by looking for nodes with the background colour #abcdef. These nodes represent toggle buttons. | |
// | |
// Need to request this gist via rawgit.com (see https://stackoverflow.com/questions/17341122/link-and-execute-external-javascript-file-hosted-on-github) | |
function createButtonStyles() { | |
var css = ` | |
.toggleButton { | |
cursor: pointer; | |
} | |
.toggleButton > rect { | |
fill: #0078e7; | |
} | |
.toggleButton > text { | |
fill: #fff; | |
} | |
.toggleButton > rect:hover { | |
fill: #1088f7; | |
} | |
.toggleButton.inactive > rect { | |
fill: #888888; | |
} | |
.toggleButton.inactive > text { | |
fill: #000; | |
}`; | |
var style = document.createElementNS('http://www.w3.org/2000/svg', 'style'); | |
style.appendChild(document.createTextNode(css)); | |
document.querySelector('svg').appendChild(style); | |
} | |
function toArray(nodeList) { | |
return Array.prototype.slice.call(nodeList); | |
} | |
function toHex(cssRGBString) { | |
// If this is already a HEX string, bail | |
if (cssRGBString.indexOf('#') !== -1) { | |
return cssRGBString; | |
} | |
// Convert rgb( 1, 2 , 3) to [1,2,3] | |
var colorArray = cssRGBString.replace('rgb(', '').replace(/[ )]/g, '').split(','); | |
return colorArray.reduce(function(acc, curr) { | |
var hex = Number(curr).toString(16); | |
if (hex.length < 2) { | |
hex = '0' + hex; | |
} | |
return acc + hex; | |
}, '#'); | |
}; | |
function toRGB(cssHexString) { | |
// If this is already a HEX string, bail | |
if (cssHexString.indexOf('rgb') !== -1) { | |
return cssHexString; | |
} | |
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") | |
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; | |
cssHexString = cssHexString.replace(shorthandRegex, function(m, r, g, b) { | |
return r + r + g + g + b + b; | |
}); | |
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(cssHexString); | |
if (!result) { | |
return cssHexString; | |
} | |
return 'rgb(' + parseInt(result[1], 16) + ', ' + parseInt(result[2], 16) + ', ' + parseInt(result[3], 16) + ')' | |
}; | |
function addClickListener(node) { | |
node.addEventListener('click', toggleLayer); | |
return node; | |
} | |
function init() { | |
// Create the button styles | |
createButtonStyles(); | |
// Find the magic button string | |
var buttonContainers = toArray(document.querySelectorAll('svg foreignObject > div[style*="color: rgb(171, 205, 239)"]')); | |
buttonContainers | |
.map(generateButton) | |
.map(addClickListener); | |
} | |
function generateButton(node) { | |
var oldButton = node.querySelector('font'); | |
var oldForeignObj = node.parentElement; | |
var switchElem = oldForeignObj.parentElement; | |
var button = document.createElementNS('http://www.w3.org/2000/svg', 'g'); | |
var buttonRect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); | |
var buttonText = switchElem.querySelector('text'); | |
buttonRect.setAttributeNS(null, 'x', 0); | |
buttonRect.setAttributeNS(null, 'y', 0); | |
buttonRect.setAttributeNS(null, 'rx', 3); | |
buttonRect.setAttributeNS(null, 'ry', 3); | |
buttonRect.setAttributeNS(null, 'width', oldForeignObj.getAttributeNS(null, 'width')); | |
buttonRect.setAttributeNS(null, 'height', parseInt(oldForeignObj.getAttributeNS(null, 'height'), 10) * 1.5); | |
buttonText.textContent = oldButton.textContent.replace(/[\[\]]/g, ''); | |
buttonText.setAttributeNS(null, 'pointer-events', 'none'); | |
button.appendChild(buttonRect); | |
button.appendChild(buttonText); | |
button.setAttributeNS(null, 'data-boxes', toHex(oldButton.color)); | |
button.setAttributeNS(null, 'data-lines', toHex(oldButton.style.backgroundColor)); | |
button.setAttributeNS(null, 'data-fonts', toRGB(oldButton.color)); | |
button.setAttributeNS(null, 'pointer-events', 'all'); | |
button.setAttributeNS(null, 'class', 'toggleButton'); | |
// Replace the switch-element with our own button | |
switchElem.parentElement.replaceChild(button, switchElem); | |
return button; | |
} | |
function toggleLayer(evt) { | |
var button = evt.currentTarget; | |
var classes = button.getAttributeNS(null, 'class').split(' '); | |
var targetBoxes = '[stroke="' + button.getAttributeNS(null, 'data-boxes') + '"]'; | |
var targetLines = '[stroke="' + button.getAttributeNS(null, 'data-lines') + '"]'; | |
var targetText = 'div[style*="' + button.getAttributeNS(null, 'data-fonts') + '"]'; | |
var allSelector = [targetBoxes, targetLines, targetText].join(','); | |
if (classes.indexOf('inactive') === -1) { | |
button.setAttributeNS(null, 'class', classes.concat('inactive').join(' ')); | |
toArray(document.querySelectorAll(allSelector)).forEach(function(node) { node.style.opacity = 0.1; }); | |
} else { | |
button.setAttributeNS(null, 'class', classes.filter(function(cls) { return cls !== 'inactive'; }).join(' ')); | |
toArray(document.querySelectorAll(allSelector)).forEach(function(node) { node.style.opacity = 1; }); | |
} | |
} | |
/* | |
// This version works when we edit the SVG to add classes and groups after exporting from Draw.io | |
function init() { | |
// Apply click event handlers to each toggleButton | |
var nodes = toArray(document.querySelectorAll('.toggleButton')); | |
nodes.forEach(addClickListener); | |
} | |
function toggleLayer(evt) { | |
var button = evt.currentTarget; | |
var classes = button.getAttributeNS(null, 'class').split(' '); | |
var targetLayerSelector = button.getAttributeNS(null, 'data-layer'); | |
if (classes.indexOf('inactive') === -1) { | |
button.setAttributeNS(null, 'class', classes.concat('inactive').join(' ')); | |
toArray(document.querySelectorAll(targetLayerSelector)).forEach(function(node) { node.style.opacity = 0.1; }); | |
} else { | |
button.setAttributeNS(null, 'class', classes.filter(function(cls) { return cls !== 'inactive'; }).join(' ')); | |
toArray(document.querySelectorAll(targetLayerSelector)).forEach(function(node) { node.style.opacity = 1; }); | |
} | |
} | |
*/ | |
window.addEventListener("load", init); | |
//]]> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment