Skip to content

Instantly share code, notes, and snippets.

@justMoritz
Last active November 7, 2021 17:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justMoritz/a2e701302597db8eedc42f144f33a2b3 to your computer and use it in GitHub Desktop.
Save justMoritz/a2e701302597db8eedc42f144f33a2b3 to your computer and use it in GitHub Desktop.
Animated SVG Pipeline
<?php
/**
* This function will attempt to inline an SVG to be animated automatically:
* for example to write names, trace drawings, etc.
* The SVG can come straight from Illustrator as long as two criteria are met:
* 1.) The original Artwork. This can be a any combination of paths and polygons
* BUT requires all to be in the same group/layer (NO SUBGROUPS, SAME LEVEL!)
* This group needs to be named `animationmask`
* 2.) A custom drawn path that roughly follows the lines of the mask. This needs to
* be a single, continuous path, and put inside a group/layer named `animationpath`
*
*/
function get_animated_svg_or_img($id, $class = null, $preserveAspectRatioString = null) {
// generates random number to ensure unique IDs
$randomnum = rand(10,1000);
$randomnum = 'r'.$randomnum;
// will attempt to inline the SVG, but will print an image as fallback just in case
$animatedStringPrint = get_img_or_inline_svg($id, $class, $preserveAspectRatioString);
// adds additional styles to the style tag. Requires style tag to be present.
$animatedStringPrint =
str_replace(
'</style>',
'#animationpath{
clip-path: url(#'.$randomnum.'animationpathline);
}
#animationpath path{
fill: none;
stroke: #000;
stroke-linecap: round;
stroke-linejoin:round;
stroke-miterlimit:10;
stroke-dasharray: 100000;
stroke-dashoffset: 100000;
stroke-width: 50;
animation: svgdrawanimation 8s linear forwards;
}
@keyframes svgdrawanimation {
20% { stroke-width: 50;}
100% { stroke-width: 100; stroke-dashoffset: 0;}
}
</style>',
$animatedStringPrint
);
// turns the animationmask group into a clipPath
$animatedStringPrint =
str_replace(
'<g id="animationmask">',
'<defs><clipPath id="'.$randomnum.'animationpathline">',
$animatedStringPrint
);
$animatedStringPrint = preg_replace('/<\/g>\s*<g id=(?:\'|\")animationpath(?:\'|\")>/', "</defs></clipPath><g id='animationpath'>", $animatedStringPrint);
// adss a class to the path for external addressing
$animatedStringPrint =
str_replace(
'id=\'animationpath\'',
'id="animationpath" class="animationclass"',
$animatedStringPrint
);
// randomizes all instances of animationpath
$animatedStringPrint =
str_replace(
'animationpath',
$randomnum.'animationpath',
$animatedStringPrint
);
// returns the final markup
return $animatedStringPrint;
}
/**
* Returns either Markup for an Inline SVG, or an image tag based on what it was passed
*
* @param string $id The ID of the attachment from WP
* @param string $class Additional Classes to be printed in the string
* @param string $preserveAspectRatioString preserveAspectRatioString
* @return Returns the Image or SVG Markup
*/
function get_img_or_inline_svg($id, $class = null, $preserveAspectRatioString = null) {
$file_type = \wp_check_filetype(get_attached_file($id));
if($file_type['type'] !== 'image/svg+xml'){
if($class){
$printclass = 'class="'.$class.'"';
}else{
$printclass = '';
}
return '<img '.$printclass.' src="'.wp_get_attachment_url($id).'" alt="" />';
}
else{
return get_inline_svg_html5(file_get_contents(get_attached_file($id)), $class, $preserveAspectRatioString);
}
}
/**
* Gets inline svg html5 Description
*
* @param $svg_content The SVG content passed from the function invoking or directly
* @param string $class Additional Classes to be printed
* @param string $preserveAspectRatioString preserveAspectRatioString
* @param boolean $removeNsElements removeNsElements
* @return Returns the Markup
*/
function get_inline_svg_html5($svg_content, $class = null, $preserveAspectRatioString = null, $removeNsElements = true) {
$sxe=new \SimpleXMLElement($svg_content);
$dom_sxe = dom_import_simplexml($sxe);
$dom = new \DOMDocument('1.0');
$dom_sxe = $dom->importNode($dom_sxe, true);
$dom_sxe = $dom->appendChild($dom_sxe);
$element = $dom->childNodes->item(0);
$element->removeAttribute('id');
$viewBox = $element->getAttribute('viewBox');
if ($viewBox) {
$width = $element->getAttribute('width');
$height = $element->getAttribute('height');
$viewBoxArr = explode(' ', $viewBox);
if (!$width) {
$element->setAttribute('width', $viewBoxArr[2] - $viewBoxArr[0]);
}
if (!$height) {
$element->setAttribute('height', $viewBoxArr[3] - $viewBoxArr[1]);
}
}
if ($preserveAspectRatioString) {
$element->setAttribute('preserveAspectRatio', $preserveAspectRatioString);
}
if ($class) {
$class_attr = $dom->createAttribute('class');
$class_attr->value = $class;
$element->appendChild($class_attr);
}
if ($removeNsElements) {
$rootElement = $sxe->getNamespaces(true);
array_walk($rootElement, function($uri, $name) use($element) { $element->removeAttributeNS($uri, $name); });
}
return $dom->saveXML($dom->documentElement);
}
?>
<script>
/**
* JavaScript/jQuery:
*
* Reads the pathlength of a given jQuery selector
* and sets the CSS attributes to that exact lenght
*
* @param {[type]} $path jQuery Object (OF THE PATH!!)
*/
var _determine_path_lengh = function($path){
var path = $path.get(0);
var pathLen = path.getTotalLength();
$path.css('stroke-dasharray', pathLen);
$path.css('stroke-dashoffset', pathLen);
};
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment