SVG filters and interpolated values - javascript

I am creating a visualization with d3.js, and the effect I would like to achieve relies on a filter using feFlood and feBlend. For each path in the visualization, I need to interpolate a different flood-opacity value for the feFlood filter primitive. The filter is pretty simple:
<filter id="multiplyOverlay" x="0" y="0" width="100%" height="100%">
<feFlood flood-color="steelblue" flood-opacity=".1" />
<feBlend mode="multiply" in2="SourceGraphic"/>
</filter>
I don't believe there is any way to pass a value in to the filter. Will I need to create a new filter for each path (about 200) in the visualization with the appropriate flood-opacity value? Or is there some other way to achieve this?

If you're going to use different flood-opacities then you'll need to do multiple filters (although using 200 different opacity settings seems like overkill). (If it's any help to you, flood-opacity is a property and can be styled via CSS.)
Addition: Also remember that you can animate things with the SMIL <animate> element - if that's why you're doing the interpolation

Related

How do i get the data of the paths and shapes of an <image> tag within an svg

I am having problems with the displaying of my image with as a source an URL, the problem is that is will not show within my svg <mask> when used as a <image x="0" y="0" height="350" width="350" attr.xlink:href="URL"> I know this must work because when i place the tag anywhere else in the svg it does show, but because i want it within the <mask> i need to find a way to succeed. when i open the image in a notepad file and copy the data into the <mask> tag it works perfectly, but because i need the <image> to change when the url changes i cannot hard code it into the <mask>
therefore the solution i thought of was to convert the <image> to a string to obtain the data and put this into a variable which i can place inside the mask. But i cannot find anywhere how i should convert this if it is even possible.
i want to convert this element of my html page
<svg xmlns:attr.xlink="http://www.w3.org/2000/xlink">
<image height="350" width="350" attr.xlink:href="URL"></image>
</svg>
into this to put it in a variable:
<polygon points="135.956,125.591 137.161,130.401 142.109,130.061 137.906,132.693 139.759,137.294 135.956,134.111 132.153,137.294 134.006,132.693 129.803,130.061 134.751,130.401 "/>
<polygon points="205.763,125.24 206.968,130.05 211.915,129.71 207.713,132.343 209.566,136.943 205.763,133.76 201.96,136.943 203.812,132.343 199.61,129.71 204.557,130.05 "/>
<g>
<g>
<path d="M155.837,153.597c0,0,0.126-0.008,0.362-0.022c0.236-0.012,0.582-0.034,1.024-0.034 c0.441-0.003,0.979,0.018,1.591,0.059c0.611,0.037,1.298,0.045,2.05,0.025c0.752-0.022,1.565-0.062,2.42-0.161 c0.852-0.111,1.778-0.246,2.727-0.261c0.948-0.025,1.931-0.039,2.93,0.068c 0.498,0.049,0.989,0.105,1.484,0.129 c0.494,0.027,0.996,0.034,1.493,0.032c1.008,0.01,1.986-0.048,2.979-0.162c0.998-0.109,1.985-0.093,2.929-0.069 c0.477,0.017,0.943,0.039,1.401,0.092c0.453,0.058,0.896,0.114,1.327,0.168c0.854,0.099,1.667,0.138,2.42,0.161 c0.751,0.02,1.439,0.011,2.05-0.025c0.612-0.041,1.15-0.063,1.591-0.059c0.441,0,0.788,0.022,1.024,0.034 c0.236,0.014,0.362,0.022,0.362,0.022s-0.504,0.028-1.381,0.124 c-0.439,0.045-0.967,0.131-1.579,0.225 c-0.612,0.095-1.307,0.17-2.065,0.199c-0.756,0.035-1.579,0.056-2.451-0.006c-0.872-0.067-1.767-0.145-2.703-0.138 c-0.941-0.001-1.905,0.037-2.883,0.144c-0.981,0.124-2.014,0.198-3.018,0.195c-0.509-0.004-1.014-0.016-1.521-0.049 c-0.506-0.03-1.011-0.093-1.501-0.147c-0.977-0.108-1.944-0.145-2.882-0.144 c-0.939-0.006-1.832,0.069-2.704,0.138 c-0.872,0.062-1.695,0.04-2.451,0.006c-0.757-0.029-1.453-0.104-2.064-0.199c-0.611-0.093-1.14-0.179-1.579-0.224 C156.341,153.625,155.837,153.597,155.837,153.597z"/>
</g>
</g>
is there a way to do this in javascript/typescript? or should i try some other way. i am using angular in this project
EDIT
i am trying it this way because i do not know what to do to fix my problem in my angular application.
i am trying to show designs on productimage for a webshop, the designs consists of text elements, which the users can adjust, and most of the time a svg logo of some sorts. because the designs mostly consists out of different colors, i am working with masking to make sure the correct design is shown. The problem is that the logo is not showing but the text is and when i paste the raw data into the mask it is working only with a tag within the mask it is not. therefore i am trying to obtain the raw data out of the image tag which i now have hidden on the top of my html page

SVG fill="url(#foo)" disappears when SVGs are loaded dynamically

I am loading different SVGs dynamically within a web application built in AngularJS, I am also altering the opacity of layers within the SVGs. These SVGs have some paths with the fill pattern property as such
<defs>
<pattern id="glass-floral" patternUnits="userSpaceOnUse" width="184" height="272">
<image xlink:href="../img/glass-floral.png" x="0" y="0" width="184" height="272"/>
</pattern>
</defs>
<rect x="98.3" y="85.5" fill="url(#glass-floral)" width="365" height="318.8"/>
This all works great at first- however under some conditions these # fills simply disappear:
-
Condition 1:
If I were to switch to another SVG and back.
Result::
The # fill is still visible.
-
Condition 2:
If I were to alter the opacity of the element with the # fill.
Result::
The # fill is still visible.
-
Condition 3:
If I were to both switch to another SVG & alter the opacity of the element with the # fill.
Result::
The # fill becomes invisible.
-
This is to mean the styles all appear to still be applied normally in the code- but there is no actual visible fill to be seen. This behaviour exists as far as I can see in Chrome and slightly differently in Safari. Firefox seems to be immune.
I've tried manually flicking the element to another fill and back in the browser to see if perhaps something had cached, no luck. I still think this may somehow be the case, with how the # refers to an inline pattern defined in the <defs> which may not have been loaded yet by the AJAX but the cached CSS rule still floating around.
If it helps matters, both SVGs that I am switching between both have the same <defs> and CSS styling applied. Is perhaps the double case of the defined pattern causing an issue?
After some investigation this appears to be an issue with the browsers (Chrome/Safari possibly others) not being able to keep up with rendering fill: url(#) and opacity for the same element at the same time, at least in cases of multiple/dynamically loaded SVGs.
To solve this, apply your opacity css to a containing element around the element that has the fill: url(#), example below:
<defs>
<pattern id="glass-floral" patternUnits="userSpaceOnUse" width="184" height="272">
<image xlink:href="../img/glass-floral.png" x="0" y="0" width="184" height="272"/>
</pattern>
</defs>
<style>.opacity-class { opacity: 0.33; }</style>
<g class="opacity-class">
<rect x="98.3" y="85.5" fill="url(#glass-floral)" width="365" height="318.8"/>
</g>
This allows the browser to do both independently and not ruin your pretty pictures.
I had multiple svg elements and problem was the same ID of all pattern tags. So, using different id="" for the pattern tag of each svg element solved my problem with disappearing fill="url()" on dynamic reload...

Highcharts multiple fill colors

I'm trying figuring out how to put every other with a brigther fill color for the same serie.
Please have a look at my reference, this is what I want to accomplish.
http://imgur.com/sYW8guR
FYI: Heres a simple area chart to save you time
http://jsfiddle.net/kylander/33cutjqn/
I don't see a way to do this without either using multiple series, or writing your own complex rendering script.
Another alternative for using 2 series that works a little different than the one proposed by Sebastian:
1) User the alternateGridColor
2) set the fillColor of your series with an appropriate opacity for the alternate grid color to have the desired effect
3) use a 2nd series, which can be automatically created, to stack on top of the main data series, filled with white to cover the alternating color in the 'open' space.
Example:
http://jsfiddle.net/jlbriggs/mg4vs1dm/
Honestly, I would personally simply opt to use the alternateGridColor option as is, however.
The simples way is using two series. http://jsfiddle.net/sbochan/gba46s7L/
series: [{
name: 'USA',
data: [1,2,3,2]
}, {
name: 'USSR/Russia',
data: [null,2,3]
}]
After playing a little bit with svg i found another solution to this.
Instead of defining color you may write
color: "url(#SomePattern)"
Define the pattern in separate svg like this
<div id="defs" style="width:0px;height:0px;">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="SomePattern"
width="50" height="50"
patternUnits="userSpaceOnUse">
<rect width='50' height='50' fill='#BDDEE8'/>
<rect x='25' width='25' height='50' fill='#D4E4E9'/>
</pattern>
</defs>
</svg>
</div>
and then insert with something like
$(".highcharts-container defs").append($("#pattern-container defs").html());
Here's a demo: http://jsfiddle.net/DrathVedro/33cutjqn/2/
However, it's just a texture and it's not bound to points like in your demo.
Try
xAxis.alternateGridColor
Docs:
http://api.highcharts.com/highcharts#xAxis.alternateGridColor

Dilate and erode SVG shapes using Javascript

EDIT:
I finally found a way to erode and dilate polygons (offsetting) so that new geometry is created using Clipper library:
https://sourceforge.net/projects/jsclipper/
Live demo of Javascript Clipper:
http://jsclipper.sourceforge.net/5.0.2.1/main_demo.html
The Clipper can only handle polygons or multi-polygons (eg. polygons with holes), so for it to work with other graphical objects of SVG format, they have to be converted to straight lines. At least paths are rather easy to convert to lines using path.getTotalLength() and path.getPointAtLength() (http://whaticode.com/2012/02/01/converting-svg-paths-to-polygons/).
The other possibility is use this like technique (that does not create new geometry):
https://stackoverflow.com/a/12723835/1691517
Is there any way to erode and dilate shapes in SVG via Javascript?
I have the following SVG example:
http://jsfiddle.net/timo2012/2S4Kt/1/
There are three shapes, blue is original, green is eroded (thinned) and red is dilated (bolded). They are made in Illustrator.
I have tested erode and dilate filters, but the effect is not so good:
https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/examples/feMorphology.svg
After few hours searching over internet, I have found only examples about bitmap image eroding and dilating, but nothing about vector shapes.
I have succeeded in dilating and eroding SVG polygons using Shapely ( http://toblerity.github.com/shapely/manual.html ) in Python by sending path points via Ajax call to PHP script which makes system() call to Python script, but this method is slow and requires server to do the work that could be done client side.
This is my code for dilating and eroding in Python (as you see it is quite short):
#!/usr/bin/python26
from shapely.geometry import Polygon
from shapely.geometry import MultiPolygon
import sys
if len(sys.argv)>2:
inset=eval(sys.argv[1])
coords=eval(sys.argv[2])
else:
sys.exit()
bowtie = Polygon(coords)
clean = bowtie.buffer(inset)
clean = clean.simplify(1, preserve_topology=False)
if clean.length>0:
if clean.geom_type=="MultiPolygon":
for n in range(0, len(clean)):
print list(clean[n].exterior.coords)
#print "\n"
elif clean.geom_type=="Polygon":
print list(clean.exterior.coords)
Also find this document, which tries to define dilate and erode in mathematical terms:
http://en.wikipedia.org/wiki/Mathematical_morphology
There is a sentence "The basic idea in binary morphology is to probe an image with a simple, pre-defined shape, drawing conclusions on how this shape fits or misses the shapes in the image. This simple "probe" is called structuring element, and is itself a binary image (i.e., a subset of the space or grid)."
I assume that this method could be used in morphing vector shapes, but how...
EDIT: One comment in a reply raised a possible issue of using filters instead of creating new geometry: if someone wants to add drag handles to polygon points, then drag handles may seem to be in wrong place. This can be acceptable, because then the impression is that the original path data is untouched, which is actually the case in filters, but - after further testing - it proved that the quality is a bigger problem. According to this and this SVG filter uses pixel representation of vector graphic object instead of path data itself, which leads to not so good looking results.
EDIT2: POSSIBLE WORKAROUND: One of the answers in this page led me to use variable-width strokes and mask to achieve a good looking workaround to this issue. I made a few tests and get implemented an Adobe Illustrator -like Offset Path Effect.
You can sort of get what you seem to be after by stroking with different stroke-widths in combination with clip-path or mask. Here's an example, some explanations of how it's constructed see here and here (arrow up or down to see some other slides on that example).
It doesn't give you new geometry though, just something that might look like new geometry.
Have you actually tested SVG's native filters? This looks close enough:
<svg width="612" height="792" viewBox="0 0 612 792" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="erode">
<feMorphology operator="erode" in="SourceGraphic" radius="12" />
</filter>
<filter id="dilate">
<feMorphology operator="dilate" in="SourceGraphic" radius="8" />
</filter>
<path id="original_path" d="M193.193,85c23.44,0.647,45.161,0.774,62,12c1.596,1.064,12,11.505,12,13
c0,2.941,8.191,5.669,3,12c-3.088,3.767-6.01-0.758-11-1c-19.56-0.948-33.241,12.296-33,34c0.163,14.698,8.114,24.492,4,41
c-1.408,5.649-6.571,15.857-10,21c-2.484,3.726-7.898,10.784-12,13c-4.115-11.677,2.686-27.29-6-35c-6.693-5.942-20.021-4.051-26,1
c-13.573,11.466-11.885,41.492-7,58c-5.8,1.772-18.938,7.685-23,12c-6.752-10.805-15.333-17.333-24-26c-3.307-3.307-9.371-12-15-12
c-16.772,0-13.963-15.741-13-28c1.283-16.324,1.727-28.24,4-42c1.276-7.72,8-16.411,8-23c0-7.416,15.945-29,23-29
c4.507,0,17.678-8.701,24-11C164.853,90.76,178.27,88.546,193.193,85"/>
</defs>
<use xlink:href="#original_path" fill="#f00" filter="url(#dilate)"></use>
<use xlink:href="#original_path" fill="blue"></use>
<use xlink:href="#original_path" fill="#1CFF00" filter="url(#erode)"></use>
</svg>
There is some clipping going on the dilate filter that can't seem to be resolved by increasing the filter region, but other than that it's pretty close to your illustrator rendering. Sure beats rendering server-side.
http://jsfiddle.net/5Qv5v/

Trying to create a re-usable text-box (text with a square background-colour) in SVG 1.1?

I'm trying to create (what I thought would be!) a simple re-usable bit of SVG to show three lines of text, with a background colour - to simulate a 'post-it' note.
I have found some useful code here to get the Bounds of the Text http://my.opera.com/MacDev_ed/blog/2009/01/21/getting-boundingbox-of-svg-elements which I am using.
So: I'm creating an group of text elements like this in the 'defs' section of my SVG:
<svg id="canvas" width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="post_it">
<text x="0" y="30" id="heading" class="heading">My Heading</text>
<text x="0" y="45" id="description" class="description">This will contain the description</text>
<text x="0" y="60" id="company" class="company">Very Big Company Ltd.</text>
</g>
And I'm displaying the text with a 'use' element like this:
<use id="12345" class="postit" xlink:href="#post_it" onclick="showId(this);"/>
I'm using the onclick to trigger a call to the following javascript function (defined in 'defs' section):
function showId(elem) {
post_it_rect=getBBoxAsRectElement(elem);
document.getElementById('canvas').appendChild(post_it_rect);
}
(The 'getBBoxAsRectElement(elem)' is from the link I posted).
As this stands; this works just fine - however if I change my 'use' element to position the text in a different place like this:
<use x="100" y="100" id="12345" class="postit" xlink:href="#post_it" onclick="showId(this);"/>
Now, the text displays in the correct place, but the resultant 'background-color' (actually a 'rect' element with opacity of 0.5) still shows on the top-left of the svg canvass - and the function used to calculate the rect is returning '-2' rather than '100' ('-98'?) as I need (I think).
What do I need to do to line up the 'rect' elements and the text elements ?
The author of the (very helpful article btw) script provides a more advanced script to draw a box round any 'bb' in an SVG, but I couldn't get this to work (missing 'transform' functions?).
I'm using Firefox 7.x to render the SVG ; and I'm loading a .svg file (ie, not embedded in html etc) straight from disk to test this).
Yes, you may need to compensate yourself for the x and y attributes on the <use> element for the time being, I'll try to find some time to update the blogpost and script.
Here's a draft SVG 1.1 test that among other things checks that the effect of the x and y attributes are included in the bbox. The line starting [myUse] is the one that tests this case, if it's red then that subtest failed. Chromium and Opera Next both pass that subtest, while Firefox nightly and IE9 doesn't. Note that the test itself has not gone through full review yet, and that it may still change.

Categories