Last active
November 10, 2017 14:05
-
-
Save tomgp/0a54da7de1a2a7b29dcfd2645ffcd499 to your computer and use it in GitHub Desktop.
svg path jittering
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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="path-data-polyfill.js"></script> | |
<title>Displacement</title> | |
<style> | |
.logo{ | |
width:100%; | |
height:100%; | |
} | |
.underlay{ | |
fill: #000; | |
} | |
.cyan{ | |
fill: #00ffff; | |
mix-blend-mode: multiply; | |
} | |
.magenta{ | |
fill: #ff00ff; | |
mix-blend-mode: multiply; | |
} | |
.yellow{ | |
fill: #ffff00; | |
mix-blend-mode: multiply; | |
} | |
</style> | |
</head> | |
<body> | |
<svg class="logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 351.58 90.02"> | |
<title>vogue-logo</title> | |
<path id="" class="cyan malleable" data-name="british vogue" d="M288.27,88.17a2.27,2.27,0,0,1-.1-0.41c0-.2.1-0.3,0.1-0.51h6.32c0.71,0,1-.2,1-0.51V3.89a0.75,0.75,0,0,0-.91-0.54l-0.09,0h-14c-0.61-.1-0.92.1-0.92,0.51V66.56c0.1,7.95-2.65,14.06-7.85,18.24A24.64,24.64,0,0,1,256.68,90h-0.1c-21.3.1-31.89-9-31.89-27.21V4.5a1.26,1.26,0,0,0-1.63-1.12h-6.73a0.49,0.49,0,0,1-.1-0.51,0.62,0.62,0,0,1,.1-0.41h31.59a1.09,1.09,0,0,1,0,.92H241.2c-1.43-.1-2,0.31-2,1.22V70.94q0,7.8,4.28,12.84c3.16,3.57,7.54,5.4,13.14,5.3a24.05,24.05,0,0,0,14.67-5c5.09-4.08,7.64-10,7.54-17.53V3.89c0-.41-0.31-0.51-0.92-0.51h-8.76a0.56,0.56,0,0,1-.2-0.51,1.41,1.41,0,0,1,.2-0.41h80.4V33.55a0.51,0.51,0,0,1-.61,0,35,35,0,0,0-3.16-15.18q-6.72-15-24.15-15H311.2c-0.71-.1-1,0.1-1,0.51V42.72c0,0.41.3,0.61,1,.61h3.46c6.83-.1,11.51-2.85,13.76-8.46a17.46,17.46,0,0,0,1.43-8.46,0.49,0.49,0,0,1,.41-0.1c0.1,0,.2.1,0.31,0.1V61.47a0.2,0.2,0,0,1-.4,0A23.06,23.06,0,0,0,328,52.7c-2.75-5.71-7.34-8.56-13.76-8.46h-3c-0.71-.1-1,0.1-1,0.51V86.53c0,0.31.3,0.51,1,.61h10c12.53,0,21.2-5.3,26.09-16a38.81,38.81,0,0,0,3.46-16.3,0.86,0.86,0,0,1,.82,0V88.17h-63.3ZM74.69,3.39H68.58A3,3,0,0,0,67,3.7a1.68,1.68,0,0,0-.41,1.12C66.44,5,57.47,33,39.64,88.57L39.33,88Q33.07,69.62,20.48,36C13.25,16.43,9.48,6,9.07,4.81a2.14,2.14,0,0,0-.61-1.22,0.88,0.88,0,0,0-.81-0.2H0.2A0.41,0.41,0,0,1,0,3,0.56,0.56,0,0,1,.2,2.47H31.08a1.4,1.4,0,0,1,.2.41,1.08,1.08,0,0,1-.2.51H24.76c-1.22-.1-1.63.2-1.32,0.92,0.1,0.1,7.34,20,21.91,59.61a1.66,1.66,0,0,0,.71,1.22Q65.32,5.37,65.42,5.32L65.73,4.2a0.68,0.68,0,0,0-.53-0.8H58.08a1.09,1.09,0,0,1,0-.92H74.69a1.09,1.09,0,0,1,0,.92h0Zm61.55,58.9a48.64,48.64,0,0,1-8.66,14.27,42.62,42.62,0,0,1-12,9.58A29.42,29.42,0,0,1,102,89.59,30.34,30.34,0,0,1,87.94,86a37.74,37.74,0,0,1-11.82-9.58,46.42,46.42,0,0,1-8-14.16A50.16,50.16,0,0,1,65,44.86,49.11,49.11,0,0,1,76.53,13.68,38.48,38.48,0,0,1,88.55,4,27.46,27.46,0,0,1,102.31.43,30,30,0,0,1,116,3.79a37.41,37.41,0,0,1,12,9.27c7.85,8.66,11.72,19.36,11.62,31.79a46.12,46.12,0,0,1-3.36,17.42h0Zm-16.3-48.1Q114.74,1,102.2,1C87.84,1,81.63,15.61,81.63,44.45c0,14.78.19,25.27,2.64,31.59,3.16,8.56,9.17,12.84,18.14,12.84,8.25,0,14.16-4.38,17.53-13.25q4-10.4,4.08-31.18c-0.1-13.35-1.43-23.54-4.08-30.26h0ZM197.79,52.7h-7a0.53,0.53,0,0,1-.2-0.41,0.77,0.77,0,0,1,.2-0.41h30.06c0,0.1.1,0.31,0.1,0.41a4.51,4.51,0,0,1-.1.51h-6.62c-0.61-.1-0.92.1-0.92,0.51V88.06c0,0.31-.2.41-0.41,0.2-0.2-1.43-1.22-2.75-3-4-2.14-1.43-4.89-1.63-8-.61A46.54,46.54,0,0,0,195,86.2l-4.48,1.94a22.55,22.55,0,0,1-9.78,1.43,27.43,27.43,0,0,1-12.84-3.77A36,36,0,0,1,157,76.45Q146.79,63.3,146.94,45.27a50.42,50.42,0,0,1,3.36-17.53,52.58,52.58,0,0,1,8.36-14.47,38.68,38.68,0,0,1,11.11-9.88c4.07-2.39,8-3.57,11.81-3.39a23.4,23.4,0,0,1,8.05,1.53l6.11,2.24a10.43,10.43,0,0,0,5.4.61A12.28,12.28,0,0,0,206.86.84a1.22,1.22,0,0,1,.51-0.51c0.2-.31.41-0.31,0.51-0.1l-0.1,30.26c0,0.31-.2.41-0.61,0.2l-1.32-5a52.23,52.23,0,0,0-3.87-10C197,6.14,190.55,1.14,182.4.84c-7.44-.41-12.84,3.77-16,12.63-2.65,7.24-3.87,17.53-3.77,31.18q0.3,42.19,16.61,44a24.45,24.45,0,0,0,11.62-1.53q8.25-3.67,8.25-13.66V53.21c0-.41-0.41-0.51-1.33-0.51h0Z" transform="translate(0.01 0.02)"></path> | |
<path id="" class="magenta malleable" data-name="british vogue" d="M288.27,88.17a2.27,2.27,0,0,1-.1-0.41c0-.2.1-0.3,0.1-0.51h6.32c0.71,0,1-.2,1-0.51V3.89a0.75,0.75,0,0,0-.91-0.54l-0.09,0h-14c-0.61-.1-0.92.1-0.92,0.51V66.56c0.1,7.95-2.65,14.06-7.85,18.24A24.64,24.64,0,0,1,256.68,90h-0.1c-21.3.1-31.89-9-31.89-27.21V4.5a1.26,1.26,0,0,0-1.63-1.12h-6.73a0.49,0.49,0,0,1-.1-0.51,0.62,0.62,0,0,1,.1-0.41h31.59a1.09,1.09,0,0,1,0,.92H241.2c-1.43-.1-2,0.31-2,1.22V70.94q0,7.8,4.28,12.84c3.16,3.57,7.54,5.4,13.14,5.3a24.05,24.05,0,0,0,14.67-5c5.09-4.08,7.64-10,7.54-17.53V3.89c0-.41-0.31-0.51-0.92-0.51h-8.76a0.56,0.56,0,0,1-.2-0.51,1.41,1.41,0,0,1,.2-0.41h80.4V33.55a0.51,0.51,0,0,1-.61,0,35,35,0,0,0-3.16-15.18q-6.72-15-24.15-15H311.2c-0.71-.1-1,0.1-1,0.51V42.72c0,0.41.3,0.61,1,.61h3.46c6.83-.1,11.51-2.85,13.76-8.46a17.46,17.46,0,0,0,1.43-8.46,0.49,0.49,0,0,1,.41-0.1c0.1,0,.2.1,0.31,0.1V61.47a0.2,0.2,0,0,1-.4,0A23.06,23.06,0,0,0,328,52.7c-2.75-5.71-7.34-8.56-13.76-8.46h-3c-0.71-.1-1,0.1-1,0.51V86.53c0,0.31.3,0.51,1,.61h10c12.53,0,21.2-5.3,26.09-16a38.81,38.81,0,0,0,3.46-16.3,0.86,0.86,0,0,1,.82,0V88.17h-63.3ZM74.69,3.39H68.58A3,3,0,0,0,67,3.7a1.68,1.68,0,0,0-.41,1.12C66.44,5,57.47,33,39.64,88.57L39.33,88Q33.07,69.62,20.48,36C13.25,16.43,9.48,6,9.07,4.81a2.14,2.14,0,0,0-.61-1.22,0.88,0.88,0,0,0-.81-0.2H0.2A0.41,0.41,0,0,1,0,3,0.56,0.56,0,0,1,.2,2.47H31.08a1.4,1.4,0,0,1,.2.41,1.08,1.08,0,0,1-.2.51H24.76c-1.22-.1-1.63.2-1.32,0.92,0.1,0.1,7.34,20,21.91,59.61a1.66,1.66,0,0,0,.71,1.22Q65.32,5.37,65.42,5.32L65.73,4.2a0.68,0.68,0,0,0-.53-0.8H58.08a1.09,1.09,0,0,1,0-.92H74.69a1.09,1.09,0,0,1,0,.92h0Zm61.55,58.9a48.64,48.64,0,0,1-8.66,14.27,42.62,42.62,0,0,1-12,9.58A29.42,29.42,0,0,1,102,89.59,30.34,30.34,0,0,1,87.94,86a37.74,37.74,0,0,1-11.82-9.58,46.42,46.42,0,0,1-8-14.16A50.16,50.16,0,0,1,65,44.86,49.11,49.11,0,0,1,76.53,13.68,38.48,38.48,0,0,1,88.55,4,27.46,27.46,0,0,1,102.31.43,30,30,0,0,1,116,3.79a37.41,37.41,0,0,1,12,9.27c7.85,8.66,11.72,19.36,11.62,31.79a46.12,46.12,0,0,1-3.36,17.42h0Zm-16.3-48.1Q114.74,1,102.2,1C87.84,1,81.63,15.61,81.63,44.45c0,14.78.19,25.27,2.64,31.59,3.16,8.56,9.17,12.84,18.14,12.84,8.25,0,14.16-4.38,17.53-13.25q4-10.4,4.08-31.18c-0.1-13.35-1.43-23.54-4.08-30.26h0ZM197.79,52.7h-7a0.53,0.53,0,0,1-.2-0.41,0.77,0.77,0,0,1,.2-0.41h30.06c0,0.1.1,0.31,0.1,0.41a4.51,4.51,0,0,1-.1.51h-6.62c-0.61-.1-0.92.1-0.92,0.51V88.06c0,0.31-.2.41-0.41,0.2-0.2-1.43-1.22-2.75-3-4-2.14-1.43-4.89-1.63-8-.61A46.54,46.54,0,0,0,195,86.2l-4.48,1.94a22.55,22.55,0,0,1-9.78,1.43,27.43,27.43,0,0,1-12.84-3.77A36,36,0,0,1,157,76.45Q146.79,63.3,146.94,45.27a50.42,50.42,0,0,1,3.36-17.53,52.58,52.58,0,0,1,8.36-14.47,38.68,38.68,0,0,1,11.11-9.88c4.07-2.39,8-3.57,11.81-3.39a23.4,23.4,0,0,1,8.05,1.53l6.11,2.24a10.43,10.43,0,0,0,5.4.61A12.28,12.28,0,0,0,206.86.84a1.22,1.22,0,0,1,.51-0.51c0.2-.31.41-0.31,0.51-0.1l-0.1,30.26c0,0.31-.2.41-0.61,0.2l-1.32-5a52.23,52.23,0,0,0-3.87-10C197,6.14,190.55,1.14,182.4.84c-7.44-.41-12.84,3.77-16,12.63-2.65,7.24-3.87,17.53-3.77,31.18q0.3,42.19,16.61,44a24.45,24.45,0,0,0,11.62-1.53q8.25-3.67,8.25-13.66V53.21c0-.41-0.41-0.51-1.33-0.51h0Z" transform="translate(0.01 0.02)"></path> | |
<path id="british_vogue" class="yellow malleable" data-name="british vogue" d="M288.27,88.17a2.27,2.27,0,0,1-.1-0.41c0-.2.1-0.3,0.1-0.51h6.32c0.71,0,1-.2,1-0.51V3.89a0.75,0.75,0,0,0-.91-0.54l-0.09,0h-14c-0.61-.1-0.92.1-0.92,0.51V66.56c0.1,7.95-2.65,14.06-7.85,18.24A24.64,24.64,0,0,1,256.68,90h-0.1c-21.3.1-31.89-9-31.89-27.21V4.5a1.26,1.26,0,0,0-1.63-1.12h-6.73a0.49,0.49,0,0,1-.1-0.51,0.62,0.62,0,0,1,.1-0.41h31.59a1.09,1.09,0,0,1,0,.92H241.2c-1.43-.1-2,0.31-2,1.22V70.94q0,7.8,4.28,12.84c3.16,3.57,7.54,5.4,13.14,5.3a24.05,24.05,0,0,0,14.67-5c5.09-4.08,7.64-10,7.54-17.53V3.89c0-.41-0.31-0.51-0.92-0.51h-8.76a0.56,0.56,0,0,1-.2-0.51,1.41,1.41,0,0,1,.2-0.41h80.4V33.55a0.51,0.51,0,0,1-.61,0,35,35,0,0,0-3.16-15.18q-6.72-15-24.15-15H311.2c-0.71-.1-1,0.1-1,0.51V42.72c0,0.41.3,0.61,1,.61h3.46c6.83-.1,11.51-2.85,13.76-8.46a17.46,17.46,0,0,0,1.43-8.46,0.49,0.49,0,0,1,.41-0.1c0.1,0,.2.1,0.31,0.1V61.47a0.2,0.2,0,0,1-.4,0A23.06,23.06,0,0,0,328,52.7c-2.75-5.71-7.34-8.56-13.76-8.46h-3c-0.71-.1-1,0.1-1,0.51V86.53c0,0.31.3,0.51,1,.61h10c12.53,0,21.2-5.3,26.09-16a38.81,38.81,0,0,0,3.46-16.3,0.86,0.86,0,0,1,.82,0V88.17h-63.3ZM74.69,3.39H68.58A3,3,0,0,0,67,3.7a1.68,1.68,0,0,0-.41,1.12C66.44,5,57.47,33,39.64,88.57L39.33,88Q33.07,69.62,20.48,36C13.25,16.43,9.48,6,9.07,4.81a2.14,2.14,0,0,0-.61-1.22,0.88,0.88,0,0,0-.81-0.2H0.2A0.41,0.41,0,0,1,0,3,0.56,0.56,0,0,1,.2,2.47H31.08a1.4,1.4,0,0,1,.2.41,1.08,1.08,0,0,1-.2.51H24.76c-1.22-.1-1.63.2-1.32,0.92,0.1,0.1,7.34,20,21.91,59.61a1.66,1.66,0,0,0,.71,1.22Q65.32,5.37,65.42,5.32L65.73,4.2a0.68,0.68,0,0,0-.53-0.8H58.08a1.09,1.09,0,0,1,0-.92H74.69a1.09,1.09,0,0,1,0,.92h0Zm61.55,58.9a48.64,48.64,0,0,1-8.66,14.27,42.62,42.62,0,0,1-12,9.58A29.42,29.42,0,0,1,102,89.59,30.34,30.34,0,0,1,87.94,86a37.74,37.74,0,0,1-11.82-9.58,46.42,46.42,0,0,1-8-14.16A50.16,50.16,0,0,1,65,44.86,49.11,49.11,0,0,1,76.53,13.68,38.48,38.48,0,0,1,88.55,4,27.46,27.46,0,0,1,102.31.43,30,30,0,0,1,116,3.79a37.41,37.41,0,0,1,12,9.27c7.85,8.66,11.72,19.36,11.62,31.79a46.12,46.12,0,0,1-3.36,17.42h0Zm-16.3-48.1Q114.74,1,102.2,1C87.84,1,81.63,15.61,81.63,44.45c0,14.78.19,25.27,2.64,31.59,3.16,8.56,9.17,12.84,18.14,12.84,8.25,0,14.16-4.38,17.53-13.25q4-10.4,4.08-31.18c-0.1-13.35-1.43-23.54-4.08-30.26h0ZM197.79,52.7h-7a0.53,0.53,0,0,1-.2-0.41,0.77,0.77,0,0,1,.2-0.41h30.06c0,0.1.1,0.31,0.1,0.41a4.51,4.51,0,0,1-.1.51h-6.62c-0.61-.1-0.92.1-0.92,0.51V88.06c0,0.31-.2.41-0.41,0.2-0.2-1.43-1.22-2.75-3-4-2.14-1.43-4.89-1.63-8-.61A46.54,46.54,0,0,0,195,86.2l-4.48,1.94a22.55,22.55,0,0,1-9.78,1.43,27.43,27.43,0,0,1-12.84-3.77A36,36,0,0,1,157,76.45Q146.79,63.3,146.94,45.27a50.42,50.42,0,0,1,3.36-17.53,52.58,52.58,0,0,1,8.36-14.47,38.68,38.68,0,0,1,11.11-9.88c4.07-2.39,8-3.57,11.81-3.39a23.4,23.4,0,0,1,8.05,1.53l6.11,2.24a10.43,10.43,0,0,0,5.4.61A12.28,12.28,0,0,0,206.86.84a1.22,1.22,0,0,1,.51-0.51c0.2-.31.41-0.31,0.51-0.1l-0.1,30.26c0,0.31-.2.41-0.61,0.2l-1.32-5a52.23,52.23,0,0,0-3.87-10C197,6.14,190.55,1.14,182.4.84c-7.44-.41-12.84,3.77-16,12.63-2.65,7.24-3.87,17.53-3.77,31.18q0.3,42.19,16.61,44a24.45,24.45,0,0,0,11.62-1.53q8.25-3.67,8.25-13.66V53.21c0-.41-0.41-0.51-1.33-0.51h0Z" transform="translate(0.01 0.02)"></path> | |
<path id="reference" class="underlay" data-name="british vogue" d="M288.27,88.17a2.27,2.27,0,0,1-.1-0.41c0-.2.1-0.3,0.1-0.51h6.32c0.71,0,1-.2,1-0.51V3.89a0.75,0.75,0,0,0-.91-0.54l-0.09,0h-14c-0.61-.1-0.92.1-0.92,0.51V66.56c0.1,7.95-2.65,14.06-7.85,18.24A24.64,24.64,0,0,1,256.68,90h-0.1c-21.3.1-31.89-9-31.89-27.21V4.5a1.26,1.26,0,0,0-1.63-1.12h-6.73a0.49,0.49,0,0,1-.1-0.51,0.62,0.62,0,0,1,.1-0.41h31.59a1.09,1.09,0,0,1,0,.92H241.2c-1.43-.1-2,0.31-2,1.22V70.94q0,7.8,4.28,12.84c3.16,3.57,7.54,5.4,13.14,5.3a24.05,24.05,0,0,0,14.67-5c5.09-4.08,7.64-10,7.54-17.53V3.89c0-.41-0.31-0.51-0.92-0.51h-8.76a0.56,0.56,0,0,1-.2-0.51,1.41,1.41,0,0,1,.2-0.41h80.4V33.55a0.51,0.51,0,0,1-.61,0,35,35,0,0,0-3.16-15.18q-6.72-15-24.15-15H311.2c-0.71-.1-1,0.1-1,0.51V42.72c0,0.41.3,0.61,1,.61h3.46c6.83-.1,11.51-2.85,13.76-8.46a17.46,17.46,0,0,0,1.43-8.46,0.49,0.49,0,0,1,.41-0.1c0.1,0,.2.1,0.31,0.1V61.47a0.2,0.2,0,0,1-.4,0A23.06,23.06,0,0,0,328,52.7c-2.75-5.71-7.34-8.56-13.76-8.46h-3c-0.71-.1-1,0.1-1,0.51V86.53c0,0.31.3,0.51,1,.61h10c12.53,0,21.2-5.3,26.09-16a38.81,38.81,0,0,0,3.46-16.3,0.86,0.86,0,0,1,.82,0V88.17h-63.3ZM74.69,3.39H68.58A3,3,0,0,0,67,3.7a1.68,1.68,0,0,0-.41,1.12C66.44,5,57.47,33,39.64,88.57L39.33,88Q33.07,69.62,20.48,36C13.25,16.43,9.48,6,9.07,4.81a2.14,2.14,0,0,0-.61-1.22,0.88,0.88,0,0,0-.81-0.2H0.2A0.41,0.41,0,0,1,0,3,0.56,0.56,0,0,1,.2,2.47H31.08a1.4,1.4,0,0,1,.2.41,1.08,1.08,0,0,1-.2.51H24.76c-1.22-.1-1.63.2-1.32,0.92,0.1,0.1,7.34,20,21.91,59.61a1.66,1.66,0,0,0,.71,1.22Q65.32,5.37,65.42,5.32L65.73,4.2a0.68,0.68,0,0,0-.53-0.8H58.08a1.09,1.09,0,0,1,0-.92H74.69a1.09,1.09,0,0,1,0,.92h0Zm61.55,58.9a48.64,48.64,0,0,1-8.66,14.27,42.62,42.62,0,0,1-12,9.58A29.42,29.42,0,0,1,102,89.59,30.34,30.34,0,0,1,87.94,86a37.74,37.74,0,0,1-11.82-9.58,46.42,46.42,0,0,1-8-14.16A50.16,50.16,0,0,1,65,44.86,49.11,49.11,0,0,1,76.53,13.68,38.48,38.48,0,0,1,88.55,4,27.46,27.46,0,0,1,102.31.43,30,30,0,0,1,116,3.79a37.41,37.41,0,0,1,12,9.27c7.85,8.66,11.72,19.36,11.62,31.79a46.12,46.12,0,0,1-3.36,17.42h0Zm-16.3-48.1Q114.74,1,102.2,1C87.84,1,81.63,15.61,81.63,44.45c0,14.78.19,25.27,2.64,31.59,3.16,8.56,9.17,12.84,18.14,12.84,8.25,0,14.16-4.38,17.53-13.25q4-10.4,4.08-31.18c-0.1-13.35-1.43-23.54-4.08-30.26h0ZM197.79,52.7h-7a0.53,0.53,0,0,1-.2-0.41,0.77,0.77,0,0,1,.2-0.41h30.06c0,0.1.1,0.31,0.1,0.41a4.51,4.51,0,0,1-.1.51h-6.62c-0.61-.1-0.92.1-0.92,0.51V88.06c0,0.31-.2.41-0.41,0.2-0.2-1.43-1.22-2.75-3-4-2.14-1.43-4.89-1.63-8-.61A46.54,46.54,0,0,0,195,86.2l-4.48,1.94a22.55,22.55,0,0,1-9.78,1.43,27.43,27.43,0,0,1-12.84-3.77A36,36,0,0,1,157,76.45Q146.79,63.3,146.94,45.27a50.42,50.42,0,0,1,3.36-17.53,52.58,52.58,0,0,1,8.36-14.47,38.68,38.68,0,0,1,11.11-9.88c4.07-2.39,8-3.57,11.81-3.39a23.4,23.4,0,0,1,8.05,1.53l6.11,2.24a10.43,10.43,0,0,0,5.4.61A12.28,12.28,0,0,0,206.86.84a1.22,1.22,0,0,1,.51-0.51c0.2-.31.41-0.31,0.51-0.1l-0.1,30.26c0,0.31-.2.41-0.61,0.2l-1.32-5a52.23,52.23,0,0,0-3.87-10C197,6.14,190.55,1.14,182.4.84c-7.44-.41-12.84,3.77-16,12.63-2.65,7.24-3.87,17.53-3.77,31.18q0.3,42.19,16.61,44a24.45,24.45,0,0,0,11.62-1.53q8.25-3.67,8.25-13.66V53.21c0-.41-0.41-0.51-1.33-0.51h0Z" transform="translate(0.01 0.02)"></path> | |
</svg> | |
</body> | |
<script> | |
const originalPathString = d3.select('path#reference').attr('d'); | |
const xyJitterElement = (e)=>{ | |
if(e.values.length > 0){ | |
e.values[0] += Math.random()*10 - 5; | |
if(e.values.length > 1){ | |
e.values[1] += Math.random()*10 - 5; | |
if(e.values.length > 2){ | |
e.values[2] += Math.random()*10 - 5; | |
} | |
} | |
} | |
return e; | |
} | |
const jitter = () => { | |
d3.selectAll('path.malleable') | |
.each(function(){ | |
const duplicatePathNode = d3.select('path#reference').node().cloneNode(); | |
const newPathData = duplicatePathNode | |
.getPathData() | |
.map(xyJitterElement); | |
duplicatePathNode.setPathData(newPathData); | |
const newPathString = d3.select(duplicatePathNode).attr('d') | |
d3.select(this) | |
.transition() | |
.attr('d', newPathString); | |
}); | |
} | |
const restore = () => { | |
d3.selectAll('path.malleable') | |
.transition() | |
.attr('d', originalPathString); | |
} | |
d3.select('svg') | |
.on('mouseover',jitter) | |
.on('mouseout',restore) | |
</script> | |
</html> |
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
// @info | |
// Polyfill for SVG getPathData() and setPathData() methods. Based on: | |
// - SVGPathSeg polyfill by Philip Rogers (MIT License) | |
// https://github.com/progers/pathseg | |
// - SVGPathNormalizer by Tadahisa Motooka (MIT License) | |
// https://github.com/motooka/SVGPathNormalizer/tree/master/src | |
// - arcToCubicCurves() by Dmitry Baranovskiy (MIT License) | |
// https://github.com/DmitryBaranovskiy/raphael/blob/v2.1.1/raphael.core.js#L1837 | |
// @author | |
// Jarosław Foksa | |
// @license | |
// MIT License | |
if (!SVGPathElement.prototype.getPathData || !SVGPathElement.prototype.setPathData) { | |
(function() { | |
var commandsMap = { | |
"Z":"Z", "M":"M", "L":"L", "C":"C", "Q":"Q", "A":"A", "H":"H", "V":"V", "S":"S", "T":"T", | |
"z":"Z", "m":"m", "l":"l", "c":"c", "q":"q", "a":"a", "h":"h", "v":"v", "s":"s", "t":"t" | |
}; | |
var Source = function(string) { | |
this._string = string; | |
this._currentIndex = 0; | |
this._endIndex = this._string.length; | |
this._prevCommand = null; | |
this._skipOptionalSpaces(); | |
}; | |
var isIE = window.navigator.userAgent.indexOf("MSIE ") !== -1; | |
Source.prototype = { | |
parseSegment: function() { | |
var char = this._string[this._currentIndex]; | |
var command = commandsMap[char] ? commandsMap[char] : null; | |
if (command === null) { | |
// Possibly an implicit command. Not allowed if this is the first command. | |
if (this._prevCommand === null) { | |
return null; | |
} | |
// Check for remaining coordinates in the current command. | |
if ( | |
(char === "+" || char === "-" || char === "." || (char >= "0" && char <= "9")) && this._prevCommand !== "Z" | |
) { | |
if (this._prevCommand === "M") { | |
command = "L"; | |
} | |
else if (this._prevCommand === "m") { | |
command = "l"; | |
} | |
else { | |
command = this._prevCommand; | |
} | |
} | |
else { | |
command = null; | |
} | |
if (command === null) { | |
return null; | |
} | |
} | |
else { | |
this._currentIndex += 1; | |
} | |
this._prevCommand = command; | |
var values = null; | |
var cmd = command.toUpperCase(); | |
if (cmd === "H" || cmd === "V") { | |
values = [this._parseNumber()]; | |
} | |
else if (cmd === "M" || cmd === "L" || cmd === "T") { | |
values = [this._parseNumber(), this._parseNumber()]; | |
} | |
else if (cmd === "S" || cmd === "Q") { | |
values = [this._parseNumber(), this._parseNumber(), this._parseNumber(), this._parseNumber()]; | |
} | |
else if (cmd === "C") { | |
values = [ | |
this._parseNumber(), | |
this._parseNumber(), | |
this._parseNumber(), | |
this._parseNumber(), | |
this._parseNumber(), | |
this._parseNumber() | |
]; | |
} | |
else if (cmd === "A") { | |
values = [ | |
this._parseNumber(), | |
this._parseNumber(), | |
this._parseNumber(), | |
this._parseArcFlag(), | |
this._parseArcFlag(), | |
this._parseNumber(), | |
this._parseNumber() | |
]; | |
} | |
else if (cmd === "Z") { | |
this._skipOptionalSpaces(); | |
values = []; | |
} | |
if (values === null || values.indexOf(null) >= 0) { | |
// Unknown command or known command with invalid values | |
return null; | |
} | |
else { | |
return {type: command, values: values}; | |
} | |
}, | |
hasMoreData: function() { | |
return this._currentIndex < this._endIndex; | |
}, | |
peekSegmentType: function() { | |
var char = this._string[this._currentIndex]; | |
return commandsMap[char] ? commandsMap[char] : null; | |
}, | |
initialCommandIsMoveTo: function() { | |
// If the path is empty it is still valid, so return true. | |
if (!this.hasMoreData()) { | |
return true; | |
} | |
var command = this.peekSegmentType(); | |
// Path must start with moveTo. | |
return command === "M" || command === "m"; | |
}, | |
_isCurrentSpace: function() { | |
var char = this._string[this._currentIndex]; | |
return char <= " " && (char === " " || char === "\n" || char === "\t" || char === "\r" || char === "\f"); | |
}, | |
_skipOptionalSpaces: function() { | |
while (this._currentIndex < this._endIndex && this._isCurrentSpace()) { | |
this._currentIndex += 1; | |
} | |
return this._currentIndex < this._endIndex; | |
}, | |
_skipOptionalSpacesOrDelimiter: function() { | |
if ( | |
this._currentIndex < this._endIndex && | |
!this._isCurrentSpace() && | |
this._string[this._currentIndex] !== "," | |
) { | |
return false; | |
} | |
if (this._skipOptionalSpaces()) { | |
if (this._currentIndex < this._endIndex && this._string[this._currentIndex] === ",") { | |
this._currentIndex += 1; | |
this._skipOptionalSpaces(); | |
} | |
} | |
return this._currentIndex < this._endIndex; | |
}, | |
// Parse a number from an SVG path. This very closely follows genericParseNumber(...) from | |
// Source/core/svg/SVGParserUtilities.cpp. | |
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF | |
_parseNumber: function() { | |
var exponent = 0; | |
var integer = 0; | |
var frac = 1; | |
var decimal = 0; | |
var sign = 1; | |
var expsign = 1; | |
var startIndex = this._currentIndex; | |
this._skipOptionalSpaces(); | |
// Read the sign. | |
if (this._currentIndex < this._endIndex && this._string[this._currentIndex] === "+") { | |
this._currentIndex += 1; | |
} | |
else if (this._currentIndex < this._endIndex && this._string[this._currentIndex] === "-") { | |
this._currentIndex += 1; | |
sign = -1; | |
} | |
if ( | |
this._currentIndex === this._endIndex || | |
( | |
(this._string[this._currentIndex] < "0" || this._string[this._currentIndex] > "9") && | |
this._string[this._currentIndex] !== "." | |
) | |
) { | |
// The first character of a number must be one of [0-9+-.]. | |
return null; | |
} | |
// Read the integer part, build right-to-left. | |
var startIntPartIndex = this._currentIndex; | |
while ( | |
this._currentIndex < this._endIndex && | |
this._string[this._currentIndex] >= "0" && | |
this._string[this._currentIndex] <= "9" | |
) { | |
this._currentIndex += 1; // Advance to first non-digit. | |
} | |
if (this._currentIndex !== startIntPartIndex) { | |
var scanIntPartIndex = this._currentIndex - 1; | |
var multiplier = 1; | |
while (scanIntPartIndex >= startIntPartIndex) { | |
integer += multiplier * (this._string[scanIntPartIndex] - "0"); | |
scanIntPartIndex -= 1; | |
multiplier *= 10; | |
} | |
} | |
// Read the decimals. | |
if (this._currentIndex < this._endIndex && this._string[this._currentIndex] === ".") { | |
this._currentIndex += 1; | |
// There must be a least one digit following the . | |
if ( | |
this._currentIndex >= this._endIndex || | |
this._string[this._currentIndex] < "0" || | |
this._string[this._currentIndex] > "9" | |
) { | |
return null; | |
} | |
while ( | |
this._currentIndex < this._endIndex && | |
this._string[this._currentIndex] >= "0" && | |
this._string[this._currentIndex] <= "9" | |
) { | |
frac *= 10; | |
decimal += (this._string.charAt(this._currentIndex) - "0") / frac; | |
this._currentIndex += 1; | |
} | |
} | |
// Read the exponent part. | |
if ( | |
this._currentIndex !== startIndex && | |
this._currentIndex + 1 < this._endIndex && | |
(this._string[this._currentIndex] === "e" || this._string[this._currentIndex] === "E") && | |
(this._string[this._currentIndex + 1] !== "x" && this._string[this._currentIndex + 1] !== "m") | |
) { | |
this._currentIndex += 1; | |
// Read the sign of the exponent. | |
if (this._string[this._currentIndex] === "+") { | |
this._currentIndex += 1; | |
} | |
else if (this._string[this._currentIndex] === "-") { | |
this._currentIndex += 1; | |
expsign = -1; | |
} | |
// There must be an exponent. | |
if ( | |
this._currentIndex >= this._endIndex || | |
this._string[this._currentIndex] < "0" || | |
this._string[this._currentIndex] > "9" | |
) { | |
return null; | |
} | |
while ( | |
this._currentIndex < this._endIndex && | |
this._string[this._currentIndex] >= "0" && | |
this._string[this._currentIndex] <= "9" | |
) { | |
exponent *= 10; | |
exponent += (this._string[this._currentIndex] - "0"); | |
this._currentIndex += 1; | |
} | |
} | |
var number = integer + decimal; | |
number *= sign; | |
if (exponent) { | |
number *= Math.pow(10, expsign * exponent); | |
} | |
if (startIndex === this._currentIndex) { | |
return null; | |
} | |
this._skipOptionalSpacesOrDelimiter(); | |
return number; | |
}, | |
_parseArcFlag: function() { | |
if (this._currentIndex >= this._endIndex) { | |
return null; | |
} | |
var flag = null; | |
var flagChar = this._string[this._currentIndex]; | |
this._currentIndex += 1; | |
if (flagChar === "0") { | |
flag = 0; | |
} | |
else if (flagChar === "1") { | |
flag = 1; | |
} | |
else { | |
return null; | |
} | |
this._skipOptionalSpacesOrDelimiter(); | |
return flag; | |
} | |
}; | |
var parsePathDataString = function(string) { | |
if (!string || string.length === 0) return []; | |
var source = new Source(string); | |
var pathData = []; | |
if (source.initialCommandIsMoveTo()) { | |
while (source.hasMoreData()) { | |
var pathSeg = source.parseSegment(); | |
if (pathSeg === null) { | |
break; | |
} | |
else { | |
pathData.push(pathSeg); | |
} | |
} | |
} | |
return pathData; | |
} | |
var setAttribute = SVGPathElement.prototype.setAttribute; | |
var removeAttribute = SVGPathElement.prototype.removeAttribute; | |
var $cachedPathData = window.Symbol ? Symbol() : "__cachedPathData"; | |
var $cachedNormalizedPathData = window.Symbol ? Symbol() : "__cachedNormalizedPathData"; | |
// @info | |
// Get an array of corresponding cubic bezier curve parameters for given arc curve paramters. | |
var arcToCubicCurves = function(x1, y1, x2, y2, r1, r2, angle, largeArcFlag, sweepFlag, _recursive) { | |
var degToRad = function(degrees) { | |
return (Math.PI * degrees) / 180; | |
}; | |
var rotate = function(x, y, angleRad) { | |
var X = x * Math.cos(angleRad) - y * Math.sin(angleRad); | |
var Y = x * Math.sin(angleRad) + y * Math.cos(angleRad); | |
return {x: X, y: Y}; | |
}; | |
var angleRad = degToRad(angle); | |
var params = []; | |
var f1, f2, cx, cy; | |
if (_recursive) { | |
f1 = _recursive[0]; | |
f2 = _recursive[1]; | |
cx = _recursive[2]; | |
cy = _recursive[3]; | |
} | |
else { | |
var p1 = rotate(x1, y1, -angleRad); | |
x1 = p1.x; | |
y1 = p1.y; | |
var p2 = rotate(x2, y2, -angleRad); | |
x2 = p2.x; | |
y2 = p2.y; | |
var x = (x1 - x2) / 2; | |
var y = (y1 - y2) / 2; | |
var h = (x * x) / (r1 * r1) + (y * y) / (r2 * r2); | |
if (h > 1) { | |
h = Math.sqrt(h); | |
r1 = h * r1; | |
r2 = h * r2; | |
} | |
var sign; | |
if (largeArcFlag === sweepFlag) { | |
sign = -1; | |
} | |
else { | |
sign = 1; | |
} | |
var r1Pow = r1 * r1; | |
var r2Pow = r2 * r2; | |
var left = r1Pow * r2Pow - r1Pow * y * y - r2Pow * x * x; | |
var right = r1Pow * y * y + r2Pow * x * x; | |
var k = sign * Math.sqrt(Math.abs(left/right)); | |
cx = k * r1 * y / r2 + (x1 + x2) / 2; | |
cy = k * -r2 * x / r1 + (y1 + y2) / 2; | |
f1 = Math.asin(parseFloat(((y1 - cy) / r2).toFixed(9))); | |
f2 = Math.asin(parseFloat(((y2 - cy) / r2).toFixed(9))); | |
if (x1 < cx) { | |
f1 = Math.PI - f1; | |
} | |
if (x2 < cx) { | |
f2 = Math.PI - f2; | |
} | |
if (f1 < 0) { | |
f1 = Math.PI * 2 + f1; | |
} | |
if (f2 < 0) { | |
f2 = Math.PI * 2 + f2; | |
} | |
if (sweepFlag && f1 > f2) { | |
f1 = f1 - Math.PI * 2; | |
} | |
if (!sweepFlag && f2 > f1) { | |
f2 = f2 - Math.PI * 2; | |
} | |
} | |
var df = f2 - f1; | |
if (Math.abs(df) > (Math.PI * 120 / 180)) { | |
var f2old = f2; | |
var x2old = x2; | |
var y2old = y2; | |
if (sweepFlag && f2 > f1) { | |
f2 = f1 + (Math.PI * 120 / 180) * (1); | |
} | |
else { | |
f2 = f1 + (Math.PI * 120 / 180) * (-1); | |
} | |
x2 = cx + r1 * Math.cos(f2); | |
y2 = cy + r2 * Math.sin(f2); | |
params = arcToCubicCurves(x2, y2, x2old, y2old, r1, r2, angle, 0, sweepFlag, [f2, f2old, cx, cy]); | |
} | |
df = f2 - f1; | |
var c1 = Math.cos(f1); | |
var s1 = Math.sin(f1); | |
var c2 = Math.cos(f2); | |
var s2 = Math.sin(f2); | |
var t = Math.tan(df / 4); | |
var hx = 4 / 3 * r1 * t; | |
var hy = 4 / 3 * r2 * t; | |
var m1 = [x1, y1]; | |
var m2 = [x1 + hx * s1, y1 - hy * c1]; | |
var m3 = [x2 + hx * s2, y2 - hy * c2]; | |
var m4 = [x2, y2]; | |
m2[0] = 2 * m1[0] - m2[0]; | |
m2[1] = 2 * m1[1] - m2[1]; | |
if (_recursive) { | |
return [m2, m3, m4].concat(params); | |
} | |
else { | |
params = [m2, m3, m4].concat(params); | |
var curves = []; | |
for (var i = 0; i < params.length; i+=3) { | |
var r1 = rotate(params[i][0], params[i][1], angleRad); | |
var r2 = rotate(params[i+1][0], params[i+1][1], angleRad); | |
var r3 = rotate(params[i+2][0], params[i+2][1], angleRad); | |
curves.push([r1.x, r1.y, r2.x, r2.y, r3.x, r3.y]); | |
} | |
return curves; | |
} | |
}; | |
var clonePathData = function(pathData) { | |
return pathData.map( function(seg) { | |
return {type: seg.type, values: Array.prototype.slice.call(seg.values)} | |
}); | |
}; | |
// @info | |
// Takes any path data, returns path data that consists only from absolute commands. | |
var absolutizePathData = function(pathData) { | |
var absolutizedPathData = []; | |
var currentX = null; | |
var currentY = null; | |
var subpathX = null; | |
var subpathY = null; | |
pathData.forEach( function(seg) { | |
var type = seg.type; | |
if (type === "M") { | |
var x = seg.values[0]; | |
var y = seg.values[1]; | |
absolutizedPathData.push({type: "M", values: [x, y]}); | |
subpathX = x; | |
subpathY = y; | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "m") { | |
var x = currentX + seg.values[0]; | |
var y = currentY + seg.values[1]; | |
absolutizedPathData.push({type: "M", values: [x, y]}); | |
subpathX = x; | |
subpathY = y; | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "L") { | |
var x = seg.values[0]; | |
var y = seg.values[1]; | |
absolutizedPathData.push({type: "L", values: [x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "l") { | |
var x = currentX + seg.values[0]; | |
var y = currentY + seg.values[1]; | |
absolutizedPathData.push({type: "L", values: [x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "C") { | |
var x1 = seg.values[0]; | |
var y1 = seg.values[1]; | |
var x2 = seg.values[2]; | |
var y2 = seg.values[3]; | |
var x = seg.values[4]; | |
var y = seg.values[5]; | |
absolutizedPathData.push({type: "C", values: [x1, y1, x2, y2, x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "c") { | |
var x1 = currentX + seg.values[0]; | |
var y1 = currentY + seg.values[1]; | |
var x2 = currentX + seg.values[2]; | |
var y2 = currentY + seg.values[3]; | |
var x = currentX + seg.values[4]; | |
var y = currentY + seg.values[5]; | |
absolutizedPathData.push({type: "C", values: [x1, y1, x2, y2, x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "Q") { | |
var x1 = seg.values[0]; | |
var y1 = seg.values[1]; | |
var x = seg.values[2]; | |
var y = seg.values[3]; | |
absolutizedPathData.push({type: "Q", values: [x1, y1, x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "q") { | |
var x1 = currentX + seg.values[0]; | |
var y1 = currentY + seg.values[1]; | |
var x = currentX + seg.values[2]; | |
var y = currentY + seg.values[3]; | |
absolutizedPathData.push({type: "Q", values: [x1, y1, x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "A") { | |
var x = seg.values[5]; | |
var y = seg.values[6]; | |
absolutizedPathData.push({ | |
type: "A", | |
values: [seg.values[0], seg.values[1], seg.values[2], seg.values[3], seg.values[4], x, y] | |
}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "a") { | |
var x = currentX + seg.values[5]; | |
var y = currentY + seg.values[6]; | |
absolutizedPathData.push({ | |
type: "A", | |
values: [seg.values[0], seg.values[1], seg.values[2], seg.values[3], seg.values[4], x, y] | |
}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "H") { | |
var x = seg.values[0]; | |
absolutizedPathData.push({type: "H", values: [x]}); | |
currentX = x; | |
} | |
else if (type === "h") { | |
var x = currentX + seg.values[0]; | |
absolutizedPathData.push({type: "H", values: [x]}); | |
currentX = x; | |
} | |
else if (type === "V") { | |
var y = seg.values[0]; | |
absolutizedPathData.push({type: "V", values: [y]}); | |
currentY = y; | |
} | |
else if (type === "v") { | |
var y = currentY + seg.values[0]; | |
absolutizedPathData.push({type: "V", values: [y]}); | |
currentY = y; | |
} | |
else if (type === "S") { | |
var x2 = seg.values[0]; | |
var y2 = seg.values[1]; | |
var x = seg.values[2]; | |
var y = seg.values[3]; | |
absolutizedPathData.push({type: "S", values: [x2, y2, x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "s") { | |
var x2 = currentX + seg.values[0]; | |
var y2 = currentY + seg.values[1]; | |
var x = currentX + seg.values[2]; | |
var y = currentY + seg.values[3]; | |
absolutizedPathData.push({type: "S", values: [x2, y2, x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "T") { | |
var x = seg.values[0]; | |
var y = seg.values[1] | |
absolutizedPathData.push({type: "T", values: [x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "t") { | |
var x = currentX + seg.values[0]; | |
var y = currentY + seg.values[1] | |
absolutizedPathData.push({type: "T", values: [x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (type === "Z" || type === "z") { | |
absolutizedPathData.push({type: "Z", values: []}); | |
currentX = subpathX; | |
currentY = subpathY; | |
} | |
}); | |
return absolutizedPathData; | |
}; | |
// @info | |
// Takes path data that consists only from absolute commands, returns path data that consists only from | |
// "M", "L", "C" and "Z" commands. | |
var reducePathData = function(pathData) { | |
var reducedPathData = []; | |
var lastType = null; | |
var lastControlX = null; | |
var lastControlY = null; | |
var currentX = null; | |
var currentY = null; | |
var subpathX = null; | |
var subpathY = null; | |
pathData.forEach( function(seg) { | |
if (seg.type === "M") { | |
var x = seg.values[0]; | |
var y = seg.values[1]; | |
reducedPathData.push({type: "M", values: [x, y]}); | |
subpathX = x; | |
subpathY = y; | |
currentX = x; | |
currentY = y; | |
} | |
else if (seg.type === "C") { | |
var x1 = seg.values[0]; | |
var y1 = seg.values[1]; | |
var x2 = seg.values[2]; | |
var y2 = seg.values[3]; | |
var x = seg.values[4]; | |
var y = seg.values[5]; | |
reducedPathData.push({type: "C", values: [x1, y1, x2, y2, x, y]}); | |
lastControlX = x2; | |
lastControlY = y2; | |
currentX = x; | |
currentY = y; | |
} | |
else if (seg.type === "L") { | |
var x = seg.values[0]; | |
var y = seg.values[1]; | |
reducedPathData.push({type: "L", values: [x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else if (seg.type === "H") { | |
var x = seg.values[0]; | |
reducedPathData.push({type: "L", values: [x, currentY]}); | |
currentX = x; | |
} | |
else if (seg.type === "V") { | |
var y = seg.values[0]; | |
reducedPathData.push({type: "L", values: [currentX, y]}); | |
currentY = y; | |
} | |
else if (seg.type === "S") { | |
var x2 = seg.values[0]; | |
var y2 = seg.values[1]; | |
var x = seg.values[2]; | |
var y = seg.values[3]; | |
var cx1, cy1; | |
if (lastType === "C" || lastType === "S") { | |
cx1 = currentX + (currentX - lastControlX); | |
cy1 = currentY + (currentY - lastControlY); | |
} | |
else { | |
cx1 = currentX; | |
cy1 = currentY; | |
} | |
reducedPathData.push({type: "C", values: [cx1, cy1, x2, y2, x, y]}); | |
lastControlX = x2; | |
lastControlY = y2; | |
currentX = x; | |
currentY = y; | |
} | |
else if (seg.type === "T") { | |
var x = seg.values[0]; | |
var y = seg.values[1]; | |
var x1, y1; | |
if (lastType === "Q" || lastType === "T") { | |
x1 = currentX + (currentX - lastControlX); | |
y1 = currentY + (currentY - lastControlY); | |
} | |
else { | |
x1 = currentX; | |
y1 = currentY; | |
} | |
var cx1 = currentX + 2 * (x1 - currentX) / 3; | |
var cy1 = currentY + 2 * (y1 - currentY) / 3; | |
var cx2 = x + 2 * (x1 - x) / 3; | |
var cy2 = y + 2 * (y1 - y) / 3; | |
reducedPathData.push({type: "C", values: [cx1, cy1, cx2, cy2, x, y]}); | |
lastControlX = x1; | |
lastControlY = y1; | |
currentX = x; | |
currentY = y; | |
} | |
else if (seg.type === "Q") { | |
var x1 = seg.values[0]; | |
var y1 = seg.values[1]; | |
var x = seg.values[2]; | |
var y = seg.values[3]; | |
var cx1 = currentX + 2 * (x1 - currentX) / 3; | |
var cy1 = currentY + 2 * (y1 - currentY) / 3; | |
var cx2 = x + 2 * (x1 - x) / 3; | |
var cy2 = y + 2 * (y1 - y) / 3; | |
reducedPathData.push({type: "C", values: [cx1, cy1, cx2, cy2, x, y]}); | |
lastControlX = x1; | |
lastControlY = y1; | |
currentX = x; | |
currentY = y; | |
} | |
else if (seg.type === "A") { | |
var r1 = Math.abs(seg.values[0]); | |
var r2 = Math.abs(seg.values[1]); | |
var angle = seg.values[2]; | |
var largeArcFlag = seg.values[3]; | |
var sweepFlag = seg.values[4]; | |
var x = seg.values[5]; | |
var y = seg.values[6]; | |
if (r1 === 0 || r2 === 0) { | |
reducedPathData.push({type: "C", values: [currentX, currentY, x, y, x, y]}); | |
currentX = x; | |
currentY = y; | |
} | |
else { | |
if (currentX !== x || currentY !== y) { | |
var curves = arcToCubicCurves(currentX, currentY, x, y, r1, r2, angle, largeArcFlag, sweepFlag); | |
curves.forEach( function(curve) { | |
reducedPathData.push({type: "C", values: curve}); | |
}); | |
currentX = x; | |
currentY = y; | |
} | |
} | |
} | |
else if (seg.type === "Z") { | |
reducedPathData.push(seg); | |
currentX = subpathX; | |
currentY = subpathY; | |
} | |
lastType = seg.type; | |
}); | |
return reducedPathData; | |
}; | |
SVGPathElement.prototype.setAttribute = function(name, value) { | |
if (name === "d") { | |
this[$cachedPathData] = null; | |
this[$cachedNormalizedPathData] = null; | |
} | |
setAttribute.call(this, name, value); | |
}; | |
SVGPathElement.prototype.removeAttribute = function(name, value) { | |
if (name === "d") { | |
this[$cachedPathData] = null; | |
this[$cachedNormalizedPathData] = null; | |
} | |
removeAttribute.call(this, name); | |
}; | |
SVGPathElement.prototype.getPathData = function(options) { | |
if (options && options.normalize) { | |
if (this[$cachedNormalizedPathData]) { | |
return clonePathData(this[$cachedNormalizedPathData]); | |
} | |
else { | |
var pathData; | |
if (this[$cachedPathData]) { | |
pathData = clonePathData(this[$cachedPathData]); | |
} | |
else { | |
pathData = parsePathDataString(this.getAttribute("d") || ""); | |
this[$cachedPathData] = clonePathData(pathData); | |
} | |
var normalizedPathData = reducePathData(absolutizePathData(pathData)); | |
this[$cachedNormalizedPathData] = clonePathData(normalizedPathData); | |
return normalizedPathData; | |
} | |
} | |
else { | |
if (this[$cachedPathData]) { | |
return clonePathData(this[$cachedPathData]); | |
} | |
else { | |
var pathData = parsePathDataString(this.getAttribute("d") || ""); | |
this[$cachedPathData] = clonePathData(pathData); | |
return pathData; | |
} | |
} | |
}; | |
SVGPathElement.prototype.setPathData = function(pathData) { | |
if (pathData.length === 0) { | |
if (isIE) { | |
// @bugfix https://github.com/mbostock/d3/issues/1737 | |
this.setAttribute("d", ""); | |
} | |
else { | |
this.removeAttribute("d"); | |
} | |
} | |
else { | |
var d = ""; | |
for (var i = 0, l = pathData.length; i < l; i += 1) { | |
var seg = pathData[i]; | |
if (i > 0) { | |
d += " "; | |
} | |
d += seg.type; | |
if (seg.values && seg.values.length > 0) { | |
d += " " + seg.values.join(" "); | |
} | |
} | |
this.setAttribute("d", d); | |
} | |
}; | |
SVGRectElement.prototype.getPathData = function(options) { | |
var x = this.x.baseVal.value; | |
var y = this.y.baseVal.value; | |
var width = this.width.baseVal.value; | |
var height = this.height.baseVal.value; | |
var rx = this.hasAttribute("rx") ? this.rx.baseVal.value : this.ry.baseVal.value; | |
var ry = this.hasAttribute("ry") ? this.ry.baseVal.value : this.rx.baseVal.value; | |
if (rx > width / 2) { | |
rx = width / 2; | |
} | |
if (ry > height / 2) { | |
ry = height / 2; | |
} | |
var pathData = [ | |
{type: "M", values: [x+rx, y]}, | |
{type: "H", values: [x+width-rx]}, | |
{type: "A", values: [rx, ry, 0, 0, 1, x+width, y+ry]}, | |
{type: "V", values: [y+height-ry]}, | |
{type: "A", values: [rx, ry, 0, 0, 1, x+width-rx, y+height]}, | |
{type: "H", values: [x+rx]}, | |
{type: "A", values: [rx, ry, 0, 0, 1, x, y+height-ry]}, | |
{type: "V", values: [y+ry]}, | |
{type: "A", values: [rx, ry, 0, 0, 1, x+rx, y]}, | |
{type: "Z", values: []} | |
]; | |
// Get rid of redundant "A" segs when either rx or ry is 0 | |
pathData = pathData.filter(function(s) { | |
return s.type === "A" && (s.values[0] === 0 || s.values[1] === 0) ? false : true; | |
}); | |
if (options && options.normalize === true) { | |
pathData = reducePathData(pathData); | |
} | |
return pathData; | |
}; | |
SVGCircleElement.prototype.getPathData = function(options) { | |
var cx = this.cx.baseVal.value; | |
var cy = this.cy.baseVal.value; | |
var r = this.r.baseVal.value; | |
var pathData = [ | |
{ type: "M", values: [cx + r, cy] }, | |
{ type: "A", values: [r, r, 0, 0, 1, cx, cy+r] }, | |
{ type: "A", values: [r, r, 0, 0, 1, cx-r, cy] }, | |
{ type: "A", values: [r, r, 0, 0, 1, cx, cy-r] }, | |
{ type: "A", values: [r, r, 0, 0, 1, cx+r, cy] }, | |
{ type: "Z", values: [] } | |
]; | |
if (options && options.normalize === true) { | |
pathData = reducePathData(pathData); | |
} | |
return pathData; | |
}; | |
SVGEllipseElement.prototype.getPathData = function(options) { | |
var cx = this.cx.baseVal.value; | |
var cy = this.cy.baseVal.value; | |
var rx = this.rx.baseVal.value; | |
var ry = this.ry.baseVal.value; | |
var pathData = [ | |
{ type: "M", values: [cx + rx, cy] }, | |
{ type: "A", values: [rx, ry, 0, 0, 1, cx, cy+ry] }, | |
{ type: "A", values: [rx, ry, 0, 0, 1, cx-rx, cy] }, | |
{ type: "A", values: [rx, ry, 0, 0, 1, cx, cy-ry] }, | |
{ type: "A", values: [rx, ry, 0, 0, 1, cx+rx, cy] }, | |
{ type: "Z", values: [] } | |
]; | |
if (options && options.normalize === true) { | |
pathData = reducePathData(pathData); | |
} | |
return pathData; | |
}; | |
SVGLineElement.prototype.getPathData = function() { | |
return [ | |
{ type: "M", values: [this.x1.baseVal.value, this.y1.baseVal.value] }, | |
{ type: "L", values: [this.x2.baseVal.value, this.y2.baseVal.value] } | |
]; | |
}; | |
SVGPolylineElement.prototype.getPathData = function() { | |
var pathData = []; | |
for (var i = 0; i < this.points.numberOfItems; i += 1) { | |
var point = this.points.getItem(i); | |
pathData.push({ | |
type: (i === 0 ? "M" : "L"), | |
values: [point.x, point.y] | |
}); | |
} | |
return pathData; | |
}; | |
SVGPolygonElement.prototype.getPathData = function() { | |
var pathData = []; | |
for (var i = 0; i < this.points.numberOfItems; i += 1) { | |
var point = this.points.getItem(i); | |
pathData.push({ | |
type: (i === 0 ? "M" : "L"), | |
values: [point.x, point.y] | |
}); | |
} | |
pathData.push({ | |
type: "Z", | |
values: [] | |
}); | |
return pathData; | |
}; | |
})(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment