I'm trying to manipulate SVG drop shadows (to emulate material design elements).
An element in material design contains 3 drop shadows of varying values depending on what level of elevation they are at. The best solution I have found to emulate this with an SVG element is to use CSS filter's drop shadow. This, however, doesn't support spread. Does anyone know a workaround that would allow me to manipulate the spread of the shadow? The only solution I can think of is creating 3 separate elements, 1 for each shadow and scaling that actual element, which seems over the top.
You can manipulate the spread of a shadow using feComponentTransfer/feFuncA. For example:
<feGaussianBlur stdDeviation="5"/>
<feComponentTransfer>
<feFuncA type="gamma" exponent="0.5" amplitude="2"/>
</feComponentTransfer>
I wrote a tool mimicking Photoshop's dropshadow control outputting a valid SVG filter: you can use it (and see the source) here:http://codepen.io/mullany/pen/sJopz
Related
I'd like to do an animation to an element when hovering it.
As I do use svg-elements for both situations (standard and hover-state) I guess I must somehow manipulate the first svg-element when hovering it by editing the svg-code inline.
I basically'd need a starting point there:
How would I "redraw" in an animated manner the hover-image and not just swap it?
Do I need a 3rd party library (which)?
If I had multiple of these situations, how would I keep my code clean by not having 10 svg-codes inline within my html-source?
Thanks for your answer(s)!
The code for the svg-image(s) is here
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 800">
<defs><style>.cls-1,.cls-2{fill:none;stroke:#000;}.cls-1{stroke-miterlimit:10;stroke-width:7px;}.cls-2{stroke-linejoin:bevel;stroke-width:5px;}</style></defs>
<title>arrows_demoZeichenfläche 1</title>
<line class="cls-1" x1="325.5" y1="333" x2="325.5" y2="539"/>
<polyline class="cls-2" points="242 455.67 325.75 539.42 409.42 455.75"/><path class="cls-1" d="M670.5,135.79c0,11.62-8,11.73-8,23.35s8,11.68,8,23.3-8,11.65-8,23.28,8,11.64,8,23.26-8,11.63-8,23.25,8,11.63,8,23.25-8,11.63-8,23.25,8,11.63,8,23.25-8,11.62-8,23.25,8,11.62,8,23.25-8,11.63-8,23.25,8,11.63,8,23.25-8,11.62-8,23.25,8,11.62,8,23.25-8,11.63-8,23.25,8,11.63,8,23.25v31"/>
<polyline class="cls-2" points="587 455.67 670.75 539.42 754.42 455.75"/></svg>
You could use JavaScript to manipulate the value of the points attribute, but such changes would be sudden, so the change would look like a stop motion film.
Like this Codepen, what you could do is give a path element a stroke-dasharray that is equal to the getTotalLength of the path in order to "erase" the straight line (of the arrow) off the page, then quickly switch the value of the d attribute, and then "redraw" the line back onto the page?
However, I don't believe that's what you're looking for. I believe HTML5 Canvas, with my limited knowledge about it, would be the more feasible option for what you're trying to accomplish.
Actually, I guess it might be possible using a CSS3 3D transform, like so. The problem, however, is that the line doesn't have any depth, so when you initially set rotateX(90deg) on the path in CSS the line becomes invisible instead of appearing as a straight line...
I have a SVG logo rendered to the canvas using fabric.js, the original SVG is all black in color but I need the user to be able to change the color of each different parts of the logo, resulting in a object with multiple colors, e.g.:
wikimediauruguay.org/images/5/53/Wikimedia-logo.png
How can I achieve this? If I just use object.setFill() it changes the color of the entire object but I need to change the color of every part separately to whatever colors the user choose. Thanks.
EDIT: found the solution, just posted my answer below in case somebody else has the same question.
Perhaps someone who knows something about fabric.js would answer in a way that makes more sense for your case, but with plain old svg, an object is often a <g< element with things ( like <rect>, <path>, <ellipse>) inside. Each child of the group, can have its own event handler:
<g>
<path onclick='handle(evt)' attrs=stuff />
<rect onclick='handle(evt)' attrs=stuff />
<circle onclick='handle(evt)' attrs=stuff />
</g>
The function activated by the click can then interrogate evt.target to see which of the subelements received the click, sorta like this:
if (evt.target.nodeName=="path") {evt.target.setAttribute("fill","purple")}
Solved mi problem in a very simple way: I just needed to edit the SVG on Illustrator so that every different colored part of the logo will be on a different layer, then when I loaded the SVG via fabric.loadSVGFromURL() each layer will be treated as a different object by fabric.js, then I just could edit each object (layer) separately (setFill(), etc).
I am new to svg, as far as I saw everywhere they using svg elements within g tag, is there any particular reason for using svg elements within g tag other than applying transformation for whole set of elements?
That's a pretty important and useful reason. But other reasons you might do it are so you can:
apply the same styling (eg. fill="blue") to a set of elements,
reference to the group of objects from a use.
Not to mention the simple organisational reasons.
http://tutorials.jenkov.com/svg/g-element.html says:
The <g> element is used to group SVG shapes together. Once grouped you can transform the whole group of shapes as if it was a single shape. This is an advantage compared to a nested <svg> element which cannot be the target of transformation by itself.
I am using RaphaelJS for a project that requires vector drawing for visualization of some data.
I am not able to figure out how to push and pop transformation states.
(equivalent of context.save() and context.restore() in html5 canvas)
Can someone point me in the right direction?
thanks.
Could you explain why you need to push and pop transformation state?
In svg you don't really need to do that, the browsers do it for you. If you want a particular transform to apply to an element then just add a transform attribute to it. You can make a transform apply to many elements by using <g> elements (in Raphaël there's Paper.set, which can be used like a <g> element, and you have the Element.transform method to set the transforms).
Update:
context.save() - in svg terms this would be to take the current transformation matrix (CTM) of the element at a given time and storing it somewhere, in Raphaël I guess this might be Element.transform() (I'm not 100% sure if it includes whole stack of transformations or not, anyway, in pure svg the CTM can be fetched via the getCTM() method which is available on all elements). One way of doing this would be to insert a <g> element with the transformation you want.
context.restore() - in svg this would be equivalent to removing a transformation from the list of transforms, but note that in svg siblings don't "inherit" the transformation (this is unlike html5 canvas or OpenGL where the currently set matrix is just applied to anything you draw after setting the transform). If you want a transform to apply to many elements then you create a <g> which has the transformation that should apply to all the children of that element, and to restore you just insert elements to the parent of the <g> instead. Raphaël doesn't have any built-in support for the <g> element (unless you count Element.set, which is a similar concept), a guess for why Raphaël does this is that it's to prevent people from trying to do things like this since it becomes very easy to bloat the DOM without realizing it (remember, SVG is a retained mode graphics format, unlike canvas and OpenGL).
Is there a way to attach metadata directly to a grouping element () in an svg file? I couldn't find anything about that in the specification or elsewhere on the web, so I assume it's not possible. Perhaps there are other ways to attach element specific metadata within the svg file...
What I try to do is to create a map and attach information about adjacent countries.
Cheers.
As XML is extensible you can add attributes and element children as you wish. Here's a possible example:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:sol="http://www.sol.org">
<circle cx="10" cy="20" sol:country="ruritania" r="5"/>
</svg>
Here the svg and circle elements are in SVG namespace and sol:country is in your namespace. I believe that SVG user agents will ignore foreign namespaces. You could also use a metadata schem such as Dublin Core.
Alternatively you could use a desc element (http://www.w3.org/TR/SVG/struct.html#DescElement)
5.4 The 'desc' and 'title' elements
Each container element or graphics element in an SVG drawing can supply a 'desc' and/or a 'title' description string where the description is text-only. When the current SVG document fragment is rendered as SVG on visual media, 'desc' and 'title' elements are not rendered as part of the graphics. User agents may, however, for example, display the 'title' element as a tooltip, as the pointing device moves over particular elements. Alternate presentations are possible, both visual and aural, which display the 'desc' and 'title' elements but do not display 'path' elements or other graphics elements. This is readily achieved by using a different (perhaps user) style sheet. For deep hierarchies, and for following 'use' element references, it is sometimes desirable to allow the user to control how deep they drill down into descriptive text.