How can I get the currently-rendered (SVG) DOM when using Angular? - javascript

I have put together a simple HTML page using Angular which can update an SVG drawing. This all works nicely, and with little effort. However, I want to be able to render the SVG to a PNG file in-browser for easy download and reuse.
The SVG drawing is set up like this:
<svg viewBox="0 0 512 512" width="512" height="512" id="svg">
<linearGradient id="background-gradient" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="{{background.start}}"/>
<stop offset="100%" stop-color="{{background.end}}"/>
</linearGradient>
<linearGradient id="primary-gradient" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="{{primary.start}}"/>
<stop offset="100%" stop-color="{{primary.end}}"/>
</linearGradient>
<linearGradient id="accent-gradient" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="{{accent.start}}"/>
<stop offset="100%" stop-color="{{accent.end}}"/>
</linearGradient>
<polygon points="256,0 478,128 478,384 256,512 34,384 34,128" fill="url(#background-gradient)"/>
<path d="M256,256 m-128,0 a128,128 0 1,1 256,0 a128,128 0 1,1 -256,0 Z M208,224 m-28,0 a28,28 0 1,1 56,0 a28,28 0 1,1 -56,0 Z M304,224 m-28,0 a28,28 0 1,1 56,0 a28,28 0 1,1 -56,0 Z M256,304 m40,0 a40,40 0 1,1 -80,0 Z" fill-rule="evenodd" fill="url(#primary-gradient)"/>
<path d="M216,224 m-16,0 a16,16 0 1,1 32,0 a16,16 0 1,1 -32,0 Z M296,224 m-16,0 a16,16 0 1,1 32,0 a16,16 0 1,1 -32,0 Z" fill-rule="evenodd" fill="url(#accent-gradient)"/>
</svg>
Note that the stop-colors in the gradient come from the Angular model. When rendering to a PNG, I create an Image with the SVG source, draw that onto a JavaScript-created <canvas>, and then convert the <canvas> contents to a data: URI.
Unfortunately, this is where things break down. Using innerHTML on the SVG drawing leaves the Angular placeholders in the result, rather than replacing them as expected. This means that all of the gradients turn out to be fully black, as their color values are literally {{background.start}}, etc. Obviously this does not produce a good result ☺
So my question is this: How can I get the SVG DOM that's rendered for display, so I can create the PNG successfully?
I have been testing this in Chrome v39 and v40 (with various minor versions) on Linux. Reproduce code:
<!DOCTYPE html>
<html ng-app="BadgeCreator">
<head>
<title>Badge Creator</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<script>
var app = angular.module('BadgeCreator', [])
.config( [
'$compileProvider',
function( $compileProvider )
{
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|data):/);
}
]);
app.controller('BadgeController', ['$scope', function($scope) {
var updateDownloadLink = function() {
var ctx, mycanvas, svg_data, img, child, target = document.getElementById('svg');
// Construct an SVG image
svg_data = '<svg xmlns="http://www.w3.org/2000/svg" width="' + target.offsetWidth +
'" height="' + target.offsetHeight + '">' + target.innerHTML + '</svg>';
console.log(svg_data);
img = new Image();
img.src = "data:image/svg+xml," + encodeURIComponent(svg_data);
// Draw the SVG image to a canvas
mycanvas = document.createElement('canvas');
mycanvas.width = target.offsetWidth;
mycanvas.height = target.offsetHeight;
ctx = mycanvas.getContext("2d");
ctx.drawImage(img, 0, 0);
// Return the canvas's data
$scope.downloadUrl = mycanvas.toDataURL("image/png");
};
$scope.background = {start: '#111', end:'#333'};
$scope.primary = {start: '#c96', end:'#963'};
$scope.accent = {start: '#3cf', end:'#39c'};
$scope.$watch('background', updateDownloadLink, true);
$scope.$watch('primary', updateDownloadLink, true);
$scope.$watch('accent', updateDownloadLink, true);
}]);
</script>
<style>
.checkerback {
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee), linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size:64px 64px;
background-position:0 0, 32px 32px;
border: 1px solid #ccc;
}
</style>
</head>
<body ng-controller="BadgeController">
<div style="width:512px; height:512px; margin: 0 auto;" class="checkerback">
<svg viewBox="0 0 512 512" width="512" height="512" id="svg">
<linearGradient id="background-gradient" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="{{background.start}}"/>
<stop offset="100%" stop-color="{{background.end}}"/>
</linearGradient>
<linearGradient id="primary-gradient" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="{{primary.start}}"/>
<stop offset="100%" stop-color="{{primary.end}}"/>
</linearGradient>
<linearGradient id="accent-gradient" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="{{accent.start}}"/>
<stop offset="100%" stop-color="{{accent.end}}"/>
</linearGradient>
<polygon points="256,0 478,128 478,384 256,512 34,384 34,128" fill="url(#background-gradient)"/>
<path d="M256,256 m-128,0 a128,128 0 1,1 256,0 a128,128 0 1,1 -256,0 Z M208,224 m-28,0 a28,28 0 1,1 56,0 a28,28 0 1,1 -56,0 Z M304,224 m-28,0 a28,28 0 1,1 56,0 a28,28 0 1,1 -56,0 Z M256,304 m40,0 a40,40 0 1,1 -80,0 Z" fill-rule="evenodd" fill="url(#primary-gradient)"/>
<path d="M216,224 m-16,0 a16,16 0 1,1 32,0 a16,16 0 1,1 -32,0 Z M296,224 m-16,0 a16,16 0 1,1 32,0 a16,16 0 1,1 -32,0 Z" fill-rule="evenodd" fill="url(#accent-gradient)"/>
</svg>
</div>
<p style="text-align: right">Download image</p>
<p>Background: <input ng-model="background.start">–<input ng-model="background.end"></p>
<p>Primary: <input ng-model="primary.start">–<input ng-model="primary.end"></p>
<p>Accent: <input ng-model="accent.start">–<input ng-model="accent.end"></p>
</body>
</html>

A couple of things,
You can use the $interpolate to create a live template of your html, and then pass it the current scope to get the rendered html.
before using the img to draw it on the canvas, you must wait until the image is loaded (use its onload event)
get the <svg> elements width/height attributes to get the dimensions
Refactored code
var app = angular.module('BadgeCreator', [])
.config([
'$compileProvider',
function($compileProvider) {
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|data):/);
}
]);
app.controller('BadgeController', ['$scope', '$interpolate',
function($scope, $interpolate) {
var target = document.getElementById('svg'),
ngElement = angular.element(target),
svgExpression = $interpolate(ngElement.html()),
updateDownloadLink = function(newval, oldval, scope) {
var ctx, mycanvas, svg_data, img, child,
liveHtml = svgExpression(scope),
svgWidth = parseInt(target.getAttribute('width'), 10),
svgHeight = parseInt(target.getAttribute('height'), 10),
svg_data = '<svg xmlns="http://www.w3.org/2000/svg" width="' + svgWidth + '" height="' + svgHeight + '">' + liveHtml + '</svg>',
img = new Image();
img.onload = function() {
// Draw the SVG image to a canvas
mycanvas = document.createElement('canvas');
mycanvas.width = svgWidth;
mycanvas.height = svgHeight;
ctx = mycanvas.getContext("2d");
ctx.drawImage(img, 0, 0);
// Return the canvas's data
scope.$apply(function() {
scope.downloadUrl = mycanvas.toDataURL("image/png");
});
};
img.src = "data:image/svg+xml," + encodeURIComponent(svg_data);
};
$scope.background = { start: '#111', end: '#333' };
$scope.primary = { start: '#c96', end: '#963' };
$scope.accent = { start: '#3cf', end: '#39c' };
$scope.$watch('background', updateDownloadLink, true);
$scope.$watch('primary', updateDownloadLink, true);
$scope.$watch('accent', updateDownloadLink, true);
}
]);
.checkerback {
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee), linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 64px 64px;
background-position: 0 0, 32px 32px;
border: 1px solid #ccc;
}
<!DOCTYPE html>
<html ng-app="BadgeCreator">
<head>
<title>Badge Creator</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
</head>
<body ng-controller="BadgeController">
<div style="width:512px; height:512px; margin: 0 auto;" class="checkerback">
<svg viewBox="0 0 512 512" width="512" height="512" id="svg">
<linearGradient id="background-gradient" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="{{background.start}}" />
<stop offset="100%" stop-color="{{background.end}}" />
</linearGradient>
<linearGradient id="primary-gradient" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="{{primary.start}}" />
<stop offset="100%" stop-color="{{primary.end}}" />
</linearGradient>
<linearGradient id="accent-gradient" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="{{accent.start}}" />
<stop offset="100%" stop-color="{{accent.end}}" />
</linearGradient>
<polygon points="256,0 478,128 478,384 256,512 34,384 34,128" fill="url(#background-gradient)" />
<path d="M256,256 m-128,0 a128,128 0 1,1 256,0 a128,128 0 1,1 -256,0 Z M208,224 m-28,0 a28,28 0 1,1 56,0 a28,28 0 1,1 -56,0 Z M304,224 m-28,0 a28,28 0 1,1 56,0 a28,28 0 1,1 -56,0 Z M256,304 m40,0 a40,40 0 1,1 -80,0 Z" fill-rule="evenodd" fill="url(#primary-gradient)"
/>
<path d="M216,224 m-16,0 a16,16 0 1,1 32,0 a16,16 0 1,1 -32,0 Z M296,224 m-16,0 a16,16 0 1,1 32,0 a16,16 0 1,1 -32,0 Z" fill-rule="evenodd" fill="url(#accent-gradient)" />
</svg>
</div>
<p style="text-align: right">Download image
</p>
<p>Background:
<input ng-model="background.start">–
<input ng-model="background.end">
</p>
<p>Primary:
<input ng-model="primary.start">–
<input ng-model="primary.end">
</p>
<p>Accent:
<input ng-model="accent.start">–
<input ng-model="accent.end">
</p>
</body>
</html>

Related

Brushstroke effect using CSS/Javascript

I want to add a brush stroke effect animation on my webpage. I tried using transform but it didn't work. I want to the brush stoke to have wipe animation from left to right so that it reveal itself.
Can anyone suggest the way to do it?
You can use SVG clipPath and animation to reach this effect, take a look at Code snippet:
Take a look at comments in code for more details.
Regarding clipPathUnits="objectBoundingBox" take a look at this DOC page.
Regarding SVG animation take a look at this page.
/* create wrapper */
.brush-wrap {
position: relative;
display: inline-block;
padding: 3rem;
}
/* applying example animation (indefinite variant) */
.brush-wrap.brush-wrap--indefinite:before {
clip-path: url(#clip-indefinite);
}
/* clipping/animating object (pseudo element) */
.brush-wrap:before {
content: '';
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
background: black;
z-index: -1;
clip-path: url(#clip); /* applying clip animation */
}
.brush-wrap p {
font-size: 2rem;
text-transform: uppercase;
margin: 0;
color: white;
font-style: italic;
filter: drop-shadow(0px 0px 2px black);
}
<div class="brush-wrap">
<p>Vivamus in erat</p>
</div>
<div class="brush-wrap brush-wrap--indefinite">
<p>Vivamus (indefinite)</p>
</div>
<!-- create svg inline with clipPath and animation -->
<!-- do not hide SVG with display: none; it will disable anim/clipping -->
<svg height="0" width="0" xmlns="http://www.w3.org/2000/svg">
<defs>
<!--
square that can be animated
animating view area
user for clipping shape
-->
<!-- runs only once -->
<clipPath id="rect-cp">
<rect id="rect" x="0" y="0" width="0" height="1">
<animate
id="anim"
attributeName="width"
dur="1s"
fill="freeze"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.5,0,0.5,1"
values="0;1"
/>
</rect>
</clipPath>
<!-- indefinite example -->
<clipPath id="rect-cp-indefinite">
<rect id="rect" x="0" y="0" width="0" height="1">
<animate
id="anim-indefinite"
attributeName="width"
dur="1s"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.5,0,0.5,1"
values="0;1"
begin="0s;anim-indefinite.end+1s"
/>
</rect>
</clipPath>
<!--
clip path for shape;
clip path should use clipPathUnits="objectBoundingBox" to stretch to full size
in this case path should contain points from 0 to 1 (1px size)
-->
<clipPath id="clip" clipPathUnits="objectBoundingBox">
<use href="#brush-shape" clip-path="url(#rect-cp)" />
</clipPath>
<clipPath id="clip-indefinite" clipPathUnits="objectBoundingBox">
<use href="#brush-shape" clip-path="url(#rect-cp-indefinite)" />
</clipPath>
<!-- brush shape -->
<path id="brush-shape" d="M.261.995A.07.07 0 0 0 .257.978V.975C.258.97.255.972.257.967.259.963.255.96.257.959V.95C.256.943.259.948.257.943.256.934.255.956.255.944.255.937.254.943.253.94.252.939.253.938.254.937.257.934.257.931.26.926.267.907.277.916.284.899.293.885.287.897.29.879.295.874.308.872.312.862.288.866.246.848.22.864.207.871.2.872.188.891.175.892.176.901.161.91.156.928.143.92.138.928c0-.005-.025-.012-.022.01-.007.013.01-.01.011-.003-.001.004.006 0 .004.003L.13.942C.13.947.113.951.111.945.103.948.059.92.089.918.069.889.048.9.029.904.028.901.002.922.008.898.012.884.032.892.029.873.026.872.031.869.029.867c0-.004.002-.012.005-.014A.055.055 0 0 0 .017.85C.021.826.042.831.045.818.044.818.038.815.041.811.042.804.053.795.046.793.041.79.032.788.029.791.026.792.019.799.024.783V.782C.024.784.022.778.022.781.021.786.019.782.022.778.024.774.023.773.02.77.011.75.041.756.045.75.037.732.04.727.048.717.051.714.045.713.046.704.04.698.026.726.019.716L.02.713C.02.711.049.696.036.696.031.688.013.697.011.7.009.699.012.689.015.686c.004-.01-.008 0-.009 0A.083.083 0 0 0 .01.671C-.015.656.013.64.022.638.065.619.022.624.05.602.076.574.047.581.061.565.065.559.049.563.054.556.056.549.035.568.036.554.034.55.047.529.046.527.045.52.061.504.058.495c0-.008.021-.016.024-.022C.09.469.095.459.101.455.102.454.101.453.1.453.093.454.093.447.09.446.087.446.094.439.095.443c.003.002.008 0 .012.005.004.008.001-.003 0-.006C.1.427.133.438.124.42c0-.006.005-.003.002-.009C.12.412.106.413.104.406.104.395.105.393.098.392.088.392.105.381.108.38.117.373.133.38.141.371.143.369.143.369.143.362V.348C.142.342.143.341.151.342.164.342.166.334.179.329.161.323.132.331.118.344v.002c-.001 0 0 .006-.002.001C.113.338.115.354.112.347.107.338.107.36.1.34.098.344.1.32.101.324L.102.32C.106.32.109.307.111.316H.11L.108.32v.002c0 .006.004.01.002.005C.109.324.115.328.115.325.116.32.117.33.118.324.118.317.119.319.12.315.121.311.125.309.125.304c0-.011.001.007.002-.001.002-.008 0 .008.002.001S.122.289.131.283C.133.283.135.281.135.277.136.271.143.276.144.27.14.26.126.277.123.262.121.254.124.257.122.252S.124.252.124.25C.121.245.128.243.128.247c0 .002 0 .002 0 0A.017.017 0 0 0 .135.244C.137.244.138.239.136.239.129.233.144.217.147.217.155.202.113.217.11.212.107.209.11.217.108.216.104.212.101.22.106.206c0 0-.004.003-.002 0C.106.198.112.215.113.205.112.202.121.202.12.205.122.199.131.198.134.195.139.19.14.192.144.188.151.183.13.188.131.187.123.185.055.231.084.194.128.159.184.15.23.132.26.119.281.094.313.079.321.079.338.05.341.074c0 .004.001.001.002.002C.345.074.342.09.344.084.339.11.33.106.375.088.4.081.424.072.449.069.461.086.479.065.497.067c.07-.01.145.008.213.021a.525.525 0 0 1 .129.034C.844.128.854.123.855.13c0 .003.001.004.001.001 0-.004.002.001.003 0C.861.13.861.145.859.136.832.14.793.123.76.123c.021.019.057.01.076.03C.833.158.826.15.821.149.814.149.802.15.793.142.789.15.775.143.77.146.772.151.768.154.762.151.727.147.687.119.652.139c.037.02.079.016.115.035.043.029.096.022.135.042C.887.223.852.214.835.215.826.213.824.214.829.217c.004.001.004.005 0 .008-.005.007.02.007.025.009.009.001.01.002.01.005-.003.007.027.007.029.012C.905.263.867.262.889.269c.024.003.053.029.075.04 0 .004-.005.002-.006.004 0 .003.006.005.003.01-.002.003.001.007.006.01S.975.34.973.34c-.001.002.01.009.013.013C.996.36.983.358.981.365.977.371.964.355.965.375c.002.002.021.013.01.014-.006 0-.004.003-.01.003-.014.004.012.011.014.015C.986.411.954.416.975.425c.006.006.009.001.013.007C.989.437.984.446.985.44.987.435.984.437.984.44S.983.443.977.442C.97.441.968.442.97.448c.002.018.019.014.022.027C.988.486.961.462.958.476.962.503 1 .488.997.509.997.516.99.514.992.527.994.536.99.539.995.541.998.56.982.538.982.547c-.004.017.002.022 0 .024v.002c.003.004-.011 0-.01.009C.972.584.971.585.97.585.96.586.978.604.98.608c.008-.002.015.013.005.02C.985.637.937.619.957.635.98.649.955.642.973.668.974.674.974.68.972.679.97.696.966.692.96.693.952.691.953.703.945.698.942.699.935.701.94.71c.002.006.022.018.015.026C.955.743.952.751.951.75.95.755.936.753.94.764c.003.01.007.005.005.022.001.009-.001 0-.002.002L.939.796C.948.8.939.808.935.813.931.818.934.825.926.816.922.812.921.812.919.819S.903.814.904.82c0 .003.013.008.01.011C.91.837.926.846.93.849.929.859.927.861.93.87.926.877.906.852.903.859c-.004.009.01.012.012.023C.916.887.906.881.906.884.91.894.899.882.898.881S.888.87.887.877c-.004.014.02.018.027.028C.93.914.907.914.905.915c0 .001.008.008.004.011C.908.931.9.921.901.926.914.945.868.935.866.939.807.926.75.894.69.896.674.894.679.901.673.897.668.896.661.885.657.89.656.892.653.89.653.887.62.879.637.881.59.88.563.878.561.88.536.882.532.882.527.891.529.895.526.915.52.903.513.904.485.903.45.918.424.927.418.921.398.928.392.932c.001.009.005.002.005.011 0 .004-.001.004-.002 0C.394.937.394.945.393.943.373.954.352.952.329.962.303.968.298.993.278.992.273.994.265.996.261 1V.995zm0-.019c-.002-.009-.003.019 0 0zM.354.945C.356.942.356.942.352.943L.337.948c0 .003.014 0 .017-.003zM.097.92C.097.919.095.919.095.921.096.924.097.921.097.92zm.04-.007c0-.003-.003-.002-.003 0 0 .004.003.002.003 0zM.111.903C.111.901.11.901.109.902.106.907.111.907.111.903zM.423.902C.429.893.404.901.396.903.394.904.42.908.423.902zm.02-.006c0-.002-.012 0-.006.003C.439.9.441.898.443.896zM.09.897c.003 0-.004-.007-.003 0 .001.004.002-.001.003 0zM.451.894c-.006-.006-.007.008 0 0zM.883.87C.884.867.876.868.88.87c.002.002.002.002.003 0zM.032.84C.031.839.03.841.032.841V.84zM.038.837C.041.834.037.836.036.837c-.001.002 0 .002.002 0zm.007.001C.05.822.038.834.042.835c.002 0 .001.007.003.003zM.943.802C.943.8.94.799.942.802c.001.002.001.002.001 0zM.059.718C.058.717.057.719.059.719V.718zM.055.712c0-.008-.009.005-.002.004L.055.712zm.01.001C.064.71.062.709.062.712c0 .004.003.004.003.001zM.061.711C.063.708.057.709.058.711c-.001.003.002.003.003 0zM.981.47C.981.467.98.467.98.47c0 .002.001.002.001 0zM.985.431H.984c-.001.002.002.002.001 0zM.977.406H.975c-.002.002.004.002.002 0zM.952.39C.951.388.941.38.94.382c.001.002.012.01.012.008zM.146.371C.148.368.144.369.144.371c-.001.002.001.002.002 0zM.948.359C.948.357.931.349.935.355c0 .001.013.007.013.004zM.115.334c0-.003-.001-.002-.001 0s.001.002.001 0zM.189.33C.188.329.187.331.189.331V.33zM.103.327.102.325C.1.324.104.332.103.327zM.105.324v.002-.002zM.137.31C.141.307.165.296.154.283.154.278.179.276.163.27.16.27.147.281.153.284.154.287.147.287.145.294c0 .002 0 .002-.001 0 0-.002-.001-.002 0 0C.144.299.138.3.137.298c0-.001-.001-.002-.001 0C.136.303.13.305.129.31c.001.005.007 0 .008 0zM.16.235C.159.233.157.239.159.237L.16.235zM.827.227c0-.002-.003-.003-.003 0 0 .002.003.002.003 0zM.161.214h.001C.159.205.155.219.161.214zm.661 0C.822.212.82.212.82.214c.001.002.002.002.002 0zm.003.001C.824.214.823.216.825.216V.215zM.171.21C.17.209.169.211.171.211V.21zM.109.208c0-.003-.001-.003-.001 0 0 .002.001.002.001 0zM.123.202.122.205.123.202zm.006.001c0-.008-.001.002-.001.003L.129.203zM.852.132C.851.131.85.133.852.133V.132zM.343.09C.343.087.342.085.342.089c0 .003.001.004.001.001zM.081.976c0-.007-.003-.01.002-.011C.087.964.081.97.083.973.085.973.086.97.086.967.085.965.091.977.092.969c.001-.006.003.013.002.01C.093.978.094.971.093.976.092.98.081.979.081.976zM.073.971V.965c.002.001.002.01 0 .006zM.085.955C.084.948.087.951.088.95.092.949.086.966.085.955zM.42.939.421.937C.422.936.42.943.42.939zM.426.938C.427.935.428.937.426.939V.938zM.13.932c.003-.018.003.009 0 0zM.753.913c0-.003.002-.002.002 0 .001.003-.002.003-.002 0zM.744.911c0-.002.001-.003.002 0 0 .002-.002.002-.002 0zM.196.908C.195.899.2.907.2.909.197.911.196.91.196.908zM.674.903c0-.005.002.002.001.002L.674.903zM.666.901c-.001-.005.001-.006 0 0 0 .002 0 .002 0 0zm.002.001V.899C.67.9.67.905.668.902zM.933.891V.886v.005zM.247.879c0-.002.002-.003.002 0-.001.002-.001.002-.002 0zM.252.875c0-.004.007-.006.006-.003v.002C.261.876.251.88.252.875zM.027.87.028.867C.029.87.027.875.027.87zM.032.816.033.813c0-.001-.001.01-.001.003zM.036.815V.813v.002zM.998.546C.997.541 1.001.547 1 .548L.998.546zM.091.393c0-.002.002-.002.002 0 0 .003-.002.002-.002 0zm.023-.03L.113.359C.117.355.136.351.124.36.121.362.117.369.114.363zm-.007 0h.001c.001.002-.001.002-.001 0zM.097.335V.332v.003zM.112.317C.112.309.108.31.113.302.119.292.119.3.117.305v.002C.123.31.117.312.115.311v.004C.114.315.113.323.112.317zM.119.301C.118.297.122.292.12.3c0 .001 0 .002-.001.001zM.1.214c0-.003.001-.002.002 0C.102.217.1.216.1.214zM.112.205C.113.201.113.201.113.204.113.205.11.21.112.205zm.78-.034C.893.169.896.167.897.168c0 .006-.006.003-.005.003zM.889.169c0-.007.005.006 0 0zM.875.166A.211.211 0 0 0 .837.157L.841.15l.001.004C.844.156.845.145.844.152c0 .002 0 .002 0 0C.849.147.855.155.86.155c.005 0 .014.001.019.006 0 .006-.002.008-.004.005zM.852.156C.852.153.85.154.85.156c-.001.002.002.002.002 0zM.882.15C.88.149.881.141.882.148V.15zM.87.142C.869.136.86.144.861.134.863.127.867.141.869.135.87.133.872.133.873.135.874.144.871.15.87.142zm.006.001c.003-.01.002.009 0 0zM.23.128h.001C.232.129.229.13.23.128zM.341.069c0-.005.002.002.001.002L.341.069zM.354.07C.352.062.357.067.356.056.357.049.364.052.363.042.364.035.365.046.366.043.367.035.37.044.37.041V.039C.372.038.372.047.374.047V.04C.379.034.474-.004.45.035c-.009.004.01.003.007.01 0 .001-.008.003-.008.001C.439.043.424.048.415.042a.039.039 0 0 1-.016.007C.398.045.396.049.395.05.395.047.39.048.389.052.388.058.378.062.378.055.377.057.378.064.376.059.375.057.375.057.375.059.375.063.37.06.37.063.369.07.366.059.366.058c0 .003-.001.009-.002.005C.362.062.355.074.354.07zM.346.06c0-.007.002 0 .001.002L.346.06zM.348.057.349.056C.351.057.347.06.348.057zM.539.051c-.004-.002 0-.006.001 0 0 .004 0 .001-.001 0zM.527.047c.002-.002.002-.002.001 0 0 .001-.003.003-.001 0zm.003 0c0-.003.003.003.001.002L.53.047zM.459.042C.457.035.479.039.478.04c.003-.001.003.002 0 .003C.475.045.477.036.475.044.472.051.471.042.469.045.468.047.467.046.468.042.467.04.46.049.459.042zm.045.003c0-.005.002.002.001.002L.504.045zM.482.041c-.002-.004 0-.003 0 0 .001.002.001.002 0 0zM.697.04C.694.034.683.044.68.033L.683.027c.001-.001 0 .01.002.004.002-.007.003.008.003.001 0-.01.003.002.003.001.002-.007.002.003.006 0C.7.034.703.034.703.039.704.042.697.043.697.04zm.009 0c0-.005.008-.003.003.001C.708.043.706.042.706.04zM.667.033C.666.028.662.034.662.033.659.03.651.032.644.028.64.022.632.036.629.028.601.037.582.02.551.023.539.021.485.026.498.008.535-.012.61.011.65.019.655.021.667.017.665.03.666.029.669.028.669.024v.001c0 .005.007-.001.008.002 0 .002.005.002.003.003C.678.03.678.031.679.032.682.035.668.037.667.033zM.506.015C.505.009.504.018.506.018V.015zM.474.022V.019c-.002.003 0-.006 0-.008.001.012.004.011.002 0C.475.005.482.012.482.008c0-.003.004-.004.004 0 0 .002 0 .002.001 0 .002-.004 0 .005 0 .006.001.009.002-.017.004-.008l.001.012C.494.019.492.022.49.022.483.026.483.005.481.014c0 .003.001-.002.001.003C.482.021.48.016.48.02.481.023.472.028.474.022zM.489.014V.012c-.002 0 0 .006 0 .002zM.466.022C.467.016.468.021.468.011.47.012.467.029.466.022zM.47.016c0-.007.002.002 0 .003V.016zM.472.011C.473.007.477.007.476.013.474.008.47.018.472.011zM.465.01h.001C.467.012.464.012.465.01zm.029 0C.492.007.495.008.495.01s0 .002-.001 0zM.491.006C.49 0 .494.011.492.01L.491.006z"/>
</defs>
</svg>

SVG-graphics: cloudy border

Is it possible to draw cloudy border for rect and polygon using svg-graphics? I tried using patterns in stroke, but it does not work.
I need border like this
Thank you!
You can fake it by using a dashed stroke with an SVG filter applied. Note this will likely slow down your page, so use the filter with caution.
<svg viewBox="0 0 300 500" width="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="outline-sobel" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="0.3" result="BLUR" />
<feConvolveMatrix in="BLUR" result="TOP-SOBEL" kernelMatrix="
1 2 1
0 0 0
-1 -2 -1"/>
<feConvolveMatrix in="BLUR" result="BOTTOM-SOBEL" kernelMatrix="
-1 -2 -1
0 0 0
1 2 1"/>
<feConvolveMatrix in="BLUR" result="LEFT-SOBEL" kernelMatrix="
1 0 -1
2 0 -2
1 0 -1"/>
<feConvolveMatrix in="BLUR" result="RIGHT-SOBEL" kernelMatrix="
-1 0 1
-2 0 2
-1 0 1"/>
<feComposite in="LEFT-SOBEL" in2="RIGHT-SOBEL" result="X" />
<feComposite in="TOP-SOBEL" in2="BOTTOM-SOBEL" result="Y" />
<feComposite in="X" in2="Y" />
</filter>
<style>
.cb1{
fill: none;
stroke: tomato;
stroke-width: 10;
}
.cb2{
stroke-dasharray: 2 10;
}
.cb3{
stroke-linecap: round;
stroke-linejoin: round;
}
.cb4{
fill: tomato;
}
.cb5
{
stroke-dasharray: 1 10 .9 10 1.1 10 .8 10 .7 10;
stroke-dashoffset: 4;
filter: url(#outline-sobel);
}
.cb6 {
stroke-width: 5;
stroke-dasharray: 0 5 0.1 5 0 5 ;
}
</style>
</defs>
<rect x="10" y="10" width="80" height="30" class="cb1" />
<rect x="10" y="60" width="80" height="30" class="cb1 cb2" />
<rect x="110" y="10" width="80" height="30" class="cb1 cb2 cb3" />
<rect x="110" y="60" width="80" height="30" class="cb1 cb2 cb3 cb4" />
<rect x="210" y="10" width="80" height="30" class="cb1 cb2 cb3 cb4 cb5" />
<path d="
M210 90
h80
a 10 10 0 0 0 -12 -20
a 18 18 0 0 0 -41 4
a 13 13 0 0 0 -26 14
z"
class="cb1 cb2 cb3 cb4 cb5 cb6" />
</svg>
Play with the values on the stroke-dasharray to get different effects, I've deliberately given a slightly random look.

How to stop SVG text hover from stopping gradient fill

I want the svg background fill gradient to remain filled even hovering over text but when you hover over the text clears the fill.
I have tried moving the text around and even moving the "flag" class but no luck. Many thanks.
I have included the codepen is here: https://codepen.io/daneli84/pen/OJVZmeJ
HTML
<svg viewBox="0 0 100 100">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(5,255,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
</linearGradient>
<linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(20,0,0);stop-opacity:0.1" />
</linearGradient>
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox"
id="filter-1">
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" class="flag-blur" in="shadowOffsetOuter1" result="shadowBlurOuter1">
</feGaussianBlur>
<feColorMatrix values="0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 9 2 0" in="shadowBlurOuter1"
type="matrix" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<g id="pod">
<polygon stroke="#000000" stroke-width="1" points="5,-9 -5,-9 -10,0 -5,9 5,9 10,0" />
</g>
</defs>
<g class="pod-wrap">
<g transform="translate(50, 41)" class="flag">
<use xlink:href="#pod" class="h1 flag">
</use>
<text class="h1" alignment-baseline="middle" text-anchor="middle" font-family="Verdana" font-size="5"
fill="blue">CNI</text>
</g>
<use xlink:href="#pod" transform="translate(35, 50)" class="flag h2" />
<use xlink:href="#pod" transform="translate(65, 50)" class=" h3" />
<use xlink:href="#pod" transform="translate(50, 59)" class=" h4" />
</g>
</svg>
CSS
/* grid styling */
use {
cursor: pointer;
fill:transparent;
}
g {cursor: pointer;}
filter: url(#filter-1);
fill: url(#grad2);
}
/* other styling */
svg {
width: 700px;
flex: 1;
}
body {
di
splay: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin: 0;
height: 100vh;
font-weight: 700;
font-family: sans-serif;
}
JS
//
var flagBlur = document.querySelector('.flag-blur');
var flags = document.querySelectorAll('.flag');
//
function startPage() {
flags.forEach(flag => {
flag.onmouseover = function() {
flag.classList.add('filter-class')
TweenMax.fromTo(flagBlur, 1, {
attr: {
}
}, {
attr: {
stdDeviation: 1.2
},
ease: Power1.easeInOut
});
}
flag.onmouseleave = function() {
flag.classList.remove('filter-class')
}
})
}
startPage();
You can use the pointer-event attribute on your text element
Other options are: bounding-box | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | none, but in this case, just use none
<text
class="h1"
alignment-baseline="middle"
text-anchor="middle"
font-family="Verdana"
font-size="5"
fill="blue"
pointer-events="none"
>CNI</text>
The pointer-events attribute is a presentation attribute that allows defining whether or when an element may be the target of a mouse event.
more reading: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointer-events

Execute SVG html code every 10 seconds

I've used an html code to make a text glitch on a website, however I need to only make the animation glitch happen every 10 seconds as it's a little crazy at the moment.
Where I'm stuck is how to re-execute the html code using a JS setInterval(html, 10000). Is this even possible? Thanks!
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg">
<script>
var html = '<defs>';
html += '<filter id="glitch" x="0" y="0">';
html += '<feColorMatrix in="SourceGraphic" mode="matrix" values="1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" result="r" />';
html += '<feOffset in="r" result="r" dx="-5">';
html += '<animate attributeName="dx" attributeType="XML" values="0; -5; 0; -18; -2; -4; 0 ;-3; 0" dur="0.2s" repeatCount="indefinite" />';
html += '</feOffset>';
html += '<feColorMatrix in="SourceGraphic" mode="matrix" values="0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0" result="g"/>';
html += '<feOffset in="g" result="g" dx="-5" dy="1">';
html += '<animate attributeName="dx" attributeType="XML" values="0; 0; 0; -3; 0; 8; 0 ;-1; 0" dur="0.15s" repeatCount="indefinite" />';
html += '</feOffset>';
html += '<feColorMatrix in="SourceGraphic" mode="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0" result="b"/>';
html += '<feOffset in="b" result="b" dx="5" dy="2">'
html += '<animate attributeName="dx" attributeType="XML" values="0; 3; -1; 4; 0; 2; 0 ;18; 0" dur="0.35s" repeatCount="indefinite"/>';
html += '</feOffset>';
html += '<feBlend in="r" in2="g" mode="screen" result="blend" />';
html += '<feBlend in="blend" in2="b" mode="screen" result="blend" />';
html += '</filter>';
html += '</defs>';
</script></svg>
You don't need setInterval() for this - it can all be done in the SVG animation. Following the strategy outlined here, make a "dummy" animation element that does nothing, and tie the start/end of the other animations to it:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<animateTransform begin="myGlitch.end" id="pause" dur="10s" type="translate" attributeType="XML" attributeName="transform" />
<filter id="glitch" x="0" y="0">
<feColorMatrix in="SourceGraphic" mode="matrix" values="1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" result="r" />
<feOffset in="r" result="r" dx="-5">
<animate attributeName="dx" attributeType="XML" values="0; -5; 0; -18; -2; -4; 0 ;-3; 0" dur="0.2s" begin="0; pause.end" />
</feOffset>
<feColorMatrix in="SourceGraphic" mode="matrix" values="0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0" result="g" />
<feOffset in="g" result="g" dx="-5" dy="1">
<animate attributeName="dx" attributeType="XML" values="0; 0; 0; -3; 0; 8; 0 ;-1; 0" dur="0.15s" begin="0; pause.end" />
</feOffset>
<feColorMatrix in="SourceGraphic" mode="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0" result="b" />
<feOffset in="b" result="b" dx="5" dy="2">
<animate id="myGlitch" attributeName="dx" attributeType="XML" values="0; 3; -1; 4; 0; 2; 0 ;18; 0" dur="0.35s" begin="0; pause.end" />
</feOffset>
<feBlend in="r" in2="g" mode="screen" result="blend" />
<feBlend in="blend" in2="b" mode="screen" result="blend" />
</filter>
</defs>
</svg>
Notice that the pause animation starts after the end of the last glitch animation (begin=myGlitch.end), and each of the glitch animations start at the end of the pause element (begin="0; pause.end").

Is there any way to colorize only part of image on hover?

I would love to code simple image painting in HTML, CSS and probably jQuery also.
Let's say I have a original image, and I want make it colorized but only in part of hover (or 10x10px square or circle of image where cursor is).
I applied some filters to make it grayscale with CSS, but I have no idea how to colorize only hover part (not whole picture).
Example image of best result (keeping colorized advice would be great, but not necessarily).
You could do this using svg's mask and filter.
CodePen
var img = document.getElementById('img');
img.addEventListener('mousemove', function(e) {
document.getElementById('c').setAttribute('cx', e.clientX - img.getBoundingClientRect().left);
document.getElementById('c').setAttribute('cy', e.clientY - img.getBoundingClientRect().top);
})
<svg id="img" width="600" height="300" viewBox="0 0 600 300">
<defs>
<filter id="f" filterUnits="userSpaceOnUse">
<feColorMatrix type="saturate" values="0" />
</filter>
<mask id="m" maskUnits="userSpaceOnUse" x="0" y="0" width="600" height="300">
<circle id="c" cx="-40" cy="-40" r="40" fill="white" />
</mask>
</defs>
<image filter="url(#f)" width="600" height="300" xlink:href="http://www.lorempixel.com/600/300" />
<image mask="url(#m)" width="600" height="300" xlink:href="http://www.lorempixel.com/600/300" />
</svg>
You could also get a smooth transition on the circle edges by using radialGradient.
CodePen
var img = document.getElementById('img');
img.addEventListener('mousemove', function(e) {
var x = e.clientX - img.getBoundingClientRect().left;
var y = e.clientY - img.getBoundingClientRect().top;
document.getElementById('r').setAttribute('fx', x);
document.getElementById('r').setAttribute('fy', y);
document.getElementById('r').setAttribute('cx', x);
document.getElementById('r').setAttribute('cy', y);
});
<svg id="img" width="600" height="300" viewBox="0 0 600 300">
<defs>
<radialGradient id="r" gradientUnits="userSpaceOnUse" cx="300" cy="150" r="400" fx="300" fy="150">
<stop offset="0%" stop-color="white" />
<stop offset="10%" stop-color="white" />
<stop offset="12%" stop-color="black" />
<stop offset="100%" stop-color="black" />
</radialGradient>
<filter id="f" filterUnits="userSpaceOnUse">
<feColorMatrix type="saturate" values="0" />
</filter>
<mask id="m" maskUnits="userSpaceOnUse" x="0" y="0" width="600" height="300">
<path d="M0,0 h600 v300 h-600z" fill="url(#r)" />
</mask>
</defs>
<image filter="url(#f)" width="600" height="300" xlink:href="http://www.lorempixel.com/600/300" />
<image mask="url(#m)" width="600" height="300" xlink:href="http://www.lorempixel.com/600/300" />
</svg>
I suggest avoiding CSS filters, as it is not supported in IE at all, and doesn't look like it is in the pipeline either.
I also would prefer to greyscale my images in photoshop, to have more control over the color balance and contrast. (But I'm a designer as well).
Instead, I'm going to layer a full color image over a grayscale image, fix the position of the colorful background image, and move the position of the top div with jQuery:
HTML
<div class="greykitty">
<div class="colorfulkitty" style="top: 150px; left: 280px;">
</div>
</div>
SCSS with normalize.css
body{
background-color:whitesmoke;
}
div{
height: 400px;
width: 600px;
background-repeat: no-repeat;
}
.greykitty{
background-image: url("http://lorempixel.com/g/600/400/cats/10/");
}
.colorfulkitty{
background-image: url("http://lorempixel.com/600/400/cats/10/");
$circlesize: 150px;
height: $circlesize;
width: $circlesize;
border-radius: $circlesize;
background-attachment: fixed;
position: absolute;
}
JS with jQuery
$('.greykitty').mousemove(function (colorize) {
var X = colorize.clientX;
var Y = colorize.clientY;
$('.colorfulkitty').css("top", (Y - 75) + 'px');
$('.colorfulkitty').css("left", (X - 75) + 'px');
});
And my codepen: http://codepen.io/fontophilic/pen/XJpVje/
You can wrap you image in a HTML Element and add a div element element with box-shadow
$("figure").on('mousemove', function(e){
$('.shadow').css({
left: e.pageX - $(this).offset().left - 40,
top: e.pageY - $(this).offset().top -40
});
});
figure{
position: relative;
margin: 20px auto;
width: 480px;
height: 480px;
overflow: hidden
}
figure:hover .shadow{
opacity: 1
}
img{
width: 100%
}
.shadow{
position: absolute;
left: 80px;
top: 60px;
z-index: 1;
background: transparent;
width: 100px;
height: 100px;
opacity: 0;
transition: opacity .3s ease;
border-radius: 50%;
box-shadow: 0 0 0 60em rgba(0,0,0,.5)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<figure>
<img src=http://i.imgur.com/orn8Dgf.jpg />
<div class=shadow></div>
</figure>
Base on this, i have solution for your problem:
Use mark to overlay image
<div class="container">`
<div class="bg-image"></div>
<div class="highlight-region"></div>
</div>
Grayscale on mark instead of image's container
.container .bg-image {
opacity:0.3;
-moz-filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
-o-filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
-webkit-filter: grayscale(100%);
filter: gray;
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
height:455px;
width:606px;
}
set opacity = 0 on highlight-region
.container div.highlight-region {
height:150px;
width:150px;
border-radius: 50%;
opacity:0;
}
Demo can see here: http://jsfiddle.net/MT4T7/438/

Categories