How to expose svg pattern property? - javascript

Say we have a complex SVG pattern to use in object fill:
<svg width=650 height=680>
<defs>
<radialGradient id='rg' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>
<stop offset='10%' style='stop-color:#3d3d3d;'/>
<stop offset='80%' style='stop-color:#3d3d3d;'/>
<stop offset='100%' style='stop-color:#fa9fb5; stop-opacity:1;' /> <!-- mutate stop-color per instance/application -->
</radialGradient>
<pattern id="texture" patternUnits="userSpaceOnUse" width="5" height="5" viewBox="0 0 5 5">
<rect width='5' height='5' fill='url(#rg)'/>
</pattern>
</defs>
</svg>
And it incorporates what could be called background color. (here it is stop-color from <stop offset='100%' style='stop-color:#fa9fb5; stop-opacity:1;' />). Actually we have 28 similar patterns. We have a color pallet (17 * 9 colors). And we want to have ability to create an SVG object for example rectangle or circle that would use a pattern yet would have a color from pallet as background.
It seems like code pre generation of 28 * 17 * 9 (3808) svg patterns each of 15-30 lines would make any mobile browser crush. While tipical application scenario is to use from 100 to 400 patterns.
We could generate and regenerate patterns while app is running yet it would be a messy job - keep svg dom clean, resource leaks and such also often regeneration of patterns on fly would probably require SVG to blink and reload.
There is an option to create an interface that would allow pattern background change and implement it using say D3js for each of 28 patterns... and store them in a factory... and each time we would need to create an object we would create instance and assign to it some random theme color... While I do like such solution and probably will end up with it (could check out what is CofeeScript they say it has clear classes and inheritance model) I would really enjoy some more simpler solution.
It would be great if we could declare inside svg pattern a modifiable value alike
<stop offset='100%' style='stop-color:{ExposedPatternValue}; stop-opacity:1;' />
So that when we use pattern we would be able to set it alike
fill: url(#texture-jeans?ExposedPatternValue=#333&OtherParam=0.5);
I wonder is there anything similar/alike in SVG (1.1/1.2/2.0) or we are stuck with static fill pattern models?

Related

How to animate fill in SVG shapes along path? [duplicate]

This question already has answers here:
How to draw a fill svg?
(3 answers)
How to animate handwriting text on the web page using SVG?
(2 answers)
Closed 4 years ago.
This is quite a conundrum for a couple of days now.
I have an SVG shape that I want to animate — namely, I want it to change it's color along a specific path. A simple shape looks like this:
Shapes in my SVGs represent strokes constituting Chinese characters (Hanzi) — the example has been extracted from here:
Here are the highlights:
It has to be done on SVGs (I need scalability).
Each shape is bound by a path and filled with color.
Most SVGs will have multiple shapes, often intersecting each other.
The shapes don’t have a constant width.
Each shape will have a dedicated path/stroke guiding it's direction.
Each of the shapes has to be animated in sequence.
The animations should have a constant speed (makes it a bit tricky with different element sizes, I think).
My research so far indicates that using a fill transform will not work with such shapes:
<html>
<body>
<head>
</head>
<div style="display: flex; align-items: center; justify-content: center; position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%);">
<div style="width: 100%; height: 100%; position: relative;">
<svg
xmlns="http://www.w3.org/2000/svg"
width="38.639015mm"
height="80.743088mm"
viewBox="0 0 38.639015 80.743087"
id="svg831">
<defs>
<linearGradient id="left-to-right">
<stop offset="0" stop-color="#4DAF4C">
<animate dur="2s" attributeName="offset" fill="freeze" from="0" to="1" />
</stop>
<stop offset="0" stop-color="#fff">
<animate dur="2s" attributeName="offset" fill="freeze" from="0" to="1" />
</stop>
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-103.9336,-77.49032)">
<g
transform="matrix(0.35277777,0,0,-0.35277777,55.696164,149.58928)"
id="g823">
<path
style="fill:url(#left-to-right);stroke:none;stroke-width:0.99999994"
d="m 139.73604,123.37501 c 1.33299,-40.000002 5.667,-67.333302 12.99999,-82.000002 2.06847,-4.338361 2.99033,-6.799913 6,-12.000001 16.66701,-25.999995 36.667,-42.333293 60,-48.999998 23.33301,-6.66669 31.83301,-6.499995 25.50001,0.50001 -6.333,6.99999 -8.5,26.499998 -6.50001,58.499986 h -3.99999 l -8.00001,-43.999988 c -22,7.33332 -40.66699,21.99999 -55.99999,43.999988 -1.77033,3.225113 -4.43601,9.376455 -6,15 -4.66701,11.333303 -7.66701,34.333306 -9,69.000005 v 5 c -0.667,21.333 -1,40.333 -1,57 l 9,7 -26,12 c 0.66699,-14 1.667,-39.333 3,-76"
id="my_path" />
</g>
</g>
</svg>
</div>
</div>
</body>
</html>
I also considered clipping path, but I an not sure how to clip/unclip one object along another object realiably so that neighboring strokes are not clipped. Some other solutions need a lot of manual tinkering, which I need to avoid due to the volume of data I want to process.
EDIT: I had to edit this question as it has been — in my opinion wrongly — marked as a duplicate, as I clearly stated my restrictions (the other question has been solved by converting everything into strokes).
There is, however, a potential solution that came to my mind, but I am not sure how to proceed: I could make my red stroke so thick that it's wider than my shape, and then apply a clipping path with the exact same coordinates as my shape — then it would suffice to just animate the red stroke. But can separate objects have non-summing clipping paths?

How do I render svg images in React Native?

I've tried "react-native-remote-svg" and "react-native-svg-image"; neither of them manage to render the SVG file.
How do I handle SVG in React-native?
Example code:
import SVGImage from 'react-native-svg-image'
const EmailLogo = require('../static/others/Email.svg');
// Render etc....
<ButtonContainer>
<Button bgColor={colors.darkTeal} txtColor={colors.whiteText}
onPress={this.onSignInPress.bind(this)}>
LOG IN WITH
</Button>
<SVGImage
style={{ width: 80, height: 80 }}
source={EmailLogo}
/>
</ButtonContainer>
Result: It's a white square when it should be an email logo.
How does one handle SVG's properly in React-native?
I've been through this struggle. react-native-svg-icon helped me out, but there were some additional things that i had to do, to make it work.
First of all, this library uses react-native-svg underneath. And you need to convert your svg files into SVG objects that this library understands.
If your open your svg file with editor, it will look something like this
<svg xmlns="http://www.w3.org/2000/svg" viewBox="170.5 200.5 18.6 23">
<defs>
<style>.a{fill:#444;}.b{fill:#07b57a;}</style>
</defs>
<g transform="translate(171 201)">
<path class="a" d="M18.1,22.5H-.5V-.5H18.1ZM.5,21.5H17.1V.5H.5Z"/>
<rect class="b" width="5.4" height="1" transform="translate(9 5.4)"/>
<path class="b" d="M4.4,7.3,3,5.9l.7-.7.7.7L6.6,3.7l.7.7Z"/>
<rect class="b" width="5.4" height="1" transform="translate(9 10.5)"/>
<path class="b" d="M4.4,12.4,3,11l.7-.7.7.7L6.6,8.8l.7.7Z"/>
<rect class="b" width="5.4" height="1" transform="translate(9 15.6)"/>
<rect class="b" width="2.5" height="1" transform="translate(3.2 15.6)"/>
</g>
</svg>
You need to convert it to something like this
entry: {
svg: (
<G transform="translate(171 201)">
<Path fill="#444444" d="M-152.4-178H-171v-23h18.6V-178z M-170-179h16.6v-21H-170V-179z" />
<Rect x="-161.5" y="-195.1" fill="#07B57A" width="5.4" height="1" />
<Path
fill="#07B57A"
d="M-166.1-193.2l-1.4-1.4l0.7-0.7l0.7,0.7l2.2-2.2l0.7,0.7L-166.1-193.2z"
/>
<Rect x="-161.5" y="-190" fill="#07B57A" width="5.4" height="1" />
<Path
fill="#07B57A"
d="M-166.1-188.1l-1.4-1.4l0.7-0.7l0.7,0.7l2.2-2.2l0.7,0.7L-166.1-188.1z"
/>
<Rect x="-161.5" y="-184.9" fill="#07B57A" width="5.4" height="1" />
<Rect x="-167.3" y="-184.9" fill="#07B57A" width="2.5" height="1" />
</G>
),
viewBox: '0 0 18.6 23',
}
This is a representation of the svg file in components of react-native-svg library. One thing you need to pay attention here, is viewbox of the svg file. I am not sure why, but most of the time, it is 'off center'. I will show in screenshots below. Because of that, it cannot be displayed by the react-native-svg-icon as well. To bring it to center you can use Adobe Illustrator, or some other online tool to edit svg. One i used is http://editor.method.ac/. So, I uploaded my svg, recentered it and downloaded it again. and used that svg file to create object in my react native code.
This is my initial svg file that i uploaded to the service. if you zoom out and press cmd+a (or ctrl+a) to select all, it will highlight svg icon, like in screenshot below. You should position it to the white part, either by dragging it, or by setting X and Y on top right corner to 0s.
This is how it will look when centered
Once you save that svg file, use it to convert it to javascript object with react-native-svg components, more info on that can be found here
Once you create you svg objects, you can use it with react-native-svg-icon. You will find how to do that in the link I shared above.
I know, this is a lot of pain and seemingly over complicated, and I spent quite some time to make it work, but it is the only way I managed to accomplish it.
One other option would be to convert your svgs into font icons with icomoon.com and use it with react-native-vector-icons. but it will only work if your svgs are drawn with only one color, as multicolored ones cannot be converted to fonts
P.S. I didn't try, but maybe, libraries that you tried to use might work with centered svg file that we got from online service. Let me know if it works, then it can be helpful to other users as well.
react-native-svg-image and react-native-svg-image uses WebView to render SVG files so it do not support local files at the moment. Its written it the docs.
Use react-native-svg-uri to render SVG images in React Native from an URL or a static file. to use react-native-svg-uri you will need to link react-native-svg as well. So read docs carefully.

How to fill only a part of the SVG? [duplicate]

This question already has answers here:
Fill only Half a star with SVG
(4 answers)
Closed 5 years ago.
I want to be able to pass a number/percentage to a function that fills a part of an svg. For example in an svg of a bucket if the real life bucket is filled 90% of the way and it returns 10 liters as an integer I want the bucket svg on my website to be filled 90% of the way with blue.
I believe you can portion an SVG into parts with an ID and fill each ID based on the number the function is passed and then edit each part with some kind of jquery function? However, I feel like filling only part of an SVG must be a more popular thing to do but I haven't been able to find a straightforward/simple way of doing this?
The simplest way to do this is with a <linearGradient>.
function setWaterLevel(percent)
{
document.getElementById("stop1").setAttribute("offset", percent+"%");
document.getElementById("stop2").setAttribute("offset", percent+"%");
}
document.getElementById("slider").addEventListener("input", function(evt) {
setWaterLevel(evt.target.value);
});
setWaterLevel(0);
<svg width="300px" viewBox="0 0 100 100">
<defs>
<linearGradient id="water" x1="0" y1="1" x2="0" y2="0">
<stop id="stop1" offset="0%" stop-color="blue"/>
<stop id="stop2" offset="0%" stop-color="transparent"/>
</linearGradient>
</defs>
<polygon points="0,0, 100,0, 80,100, 20,100"
fill="url(#water)" stroke="black"/>
</svg>
<br>
<input id="slider" type="range" min="0" max="100" step="10" value="0"/>
Your best solution is probably going to be to use two <canvas> tags and write the fill portion over the container portion. That way you can calculate both separately and don't have to worry about a partial SVG file.
Doing it this way, you'll have much greater control over everything.

Confused about SVG styling with d3.js

The most d3.js examples use SVG to draw the diagrams, etc. This means for instance rect instead of div. This then again means, that CSS properties like drop-shadow cannot be applied.
The alternative approach is to define filters in <defs>. The same is true if you want to fill the rect with a gradient color. Is that right so far?
So I define some filter and gradients, but it seems very redundant to redefine these definitions for every page again. Wouldn't it be possible to reference all these definitions from a separate svg-file?
I tried things like: filter: url(.../my_file.svg) but it does not seem to work, but isn't that how it's supposed to be?
Say you have a file called filters.svg, and it contains a few filter defitions. It looks something like this:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<filter id="my_filter" x="0%" y="0%" width="100%" height="100%">
...
</filter>
</svg>
If you were using my_filter in that same document, you'd just refer to it using #my_filter. But you're not. You want to use it in another document. What you have to do then is refer to it in those documents as /filters.svg#my_filter. Like this:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="0" y="0" width="100" height="100" fill="url(/filters.svg#my_filter)" />
</svg>
This is of course assuming that both documents are accessible from the same domain, and that they're located in the right places, etc. I don't know if this will work in CSS stylesheets, but it will work across SVG documents. Check out the section on Linking in the SVG Specification for more details.

How to trace out letters like a laser

Looking for ideas on how to animate what looks like a laser drawing out a word in a cursive font using SVG. The animation can be done with SMIL or JavaScript I don't care - though I think it would be easier with SMIL.
I am pretty sure if I could just get the letters represented as a path I could figure out how to animate a line from a fixed point to the word path - even if the path is non-continuous.
Any ideas?
EDIT
My demo was very basic, essentially I wrote animate functions for each letter and arranged their timing. Here is the letter X for example:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
<rect x="0" y="0" width="100%" height="100%" fill="black"/>
<path id="word" stroke="red" d="M10 10 L40 40 M40 10 L10 40" />
<line x1="10" y1="10" x2="25" y2="50" stroke="blue" stroke-width="0.5">
<animate attributeName="x1" begin="0s" dur="1s" values="10; 40;" />
<animate attributeName="y1" begin="0s" dur="1s" values="10; 40;" />
<animate attributeName="x1" begin="1s" dur="1s" values="40; 10;" />
<animate attributeName="y1" begin="1s" dur="1s" values="10; 40;" />
<set attributeName="visibility" to="hidden" begin="2s" />
</line>
</svg>
I am sure we can all agree that this is not an ideal long term solution... I thought it would be relatively easy to animate one end of a LINE along a path but I am having problems just getting the path...
Extract the paths from the glyphs in question, then apply a dash-array animation as seen in this example on each of the paths.
From a high level perspective, I would think you would want to do something like render the font to a canvas, then use the pixel information to generate the animation sequence. A simple algorithm could just trace from left to right, it would be a good deal harder to figure out a single stroke path, but that is doable as well.
You don't mention any idea of what platform or any time constraints, so its hard to get much closer than that.
One possibility... SVG Fonts are, I understand, stored as a sequence of SVG commands used to draw individual characters. The vector-based nature of drawing in SVG would seem like it would be amenable to 'tracing out' characters in realtime; you might be able to make a conversion utility to pre-convert SVG fonts to simple paths.

Categories

Resources