SVG hamburger menu: how can I change its color every time I clicked it? - laravel

I am aware this is a pretty newbie question but I can't figure out a solution on my own.
I have the following SVG hamburger-menu icon:
<svg class="svg-menu" style="margin-top: 1.8rem;margin-right:0.5rem" viewBox="0 0 100 80" width="40" height="18" onclick='fill:red'>>
<rect id="r1" width="100" height="8"></rect>
<rect id="r2" y="30" width="100" height="8"></rect>
<rect id="r3" y="60" width="100" height="8"></rect>
</svg>
At the moment, I can change its color when I click on it by running the following function:
enter code here
$(function(){
$(".svg-menu").on("click",function(){
$("#r1,#r2,#r3").attr("fill","#C8C8C8");
});
});
enter code here
I am unable to figure out how to revert the original color back after clicking on it again (to be clear: on the first click, it changes its color and the menu appears, on the second click the menu disappears but the color remains the same).
Any lead would be greatly appreciated!
Thanks

Well, there was a similar question on StackOverflow in the past. I did a small edit on it, it seems working this way:
let clickNumbers = 0;
$(function(){
$(".svg-menu").on("click",function(){
clickNumbers++;
if(clickNumbers % 2 == 1){
$("#r1,#r2,#r3").attr("fill","#C8C8C8");
} else {
$("#r1,#r2,#r3").attr("fill","#000");
}
});
});

Related

How can I show percentages in MudCharts?

I have managed to make a basic donut chart with MudBlazor, but I can not figure out how to show the percentages of the data displayed. For instance, in the attached image I want to show 50% on each side and preferably in the middle of each half circle so it's clear which percentage belongs to the corresponding half circle. Example chart
This is what I currently have:
<MudChart ChartType="ChartType.Donut" Width="300px" Height="300px" InputData="#data" InputLabels="#labels">
</MudChart>
#code {
public double[] data = { 77, 77 };
public string[] labels = { "Oil", "Coal" };
}
Any help is much appreciated.
I'm not sure if there is a solution for your question but you can put some information inside of the donut chart. See example below. I found it in the docs.
<MudChart ChartType="ChartType.Donut" Width="300px" Height="300px"
InputData="#data" InputLabels="#labels">
<CustomGraphics>
<text class="donut-inner-text" x="47%" y="35%" dominant-baseline="middle" text-anchor="middle" fill="black" font-size="2">Total</text>
<text class="donut-inner-text" x="47%" y="50%" dominant-baseline="middle" text-anchor="middle" fill="black" font-size="5">#data.Sum().ToString()</text>
</CustomGraphics>
</MudChart>

SVG Logo animation

So I have a client logo and I want to animate it on scroll. Let's say that the logo is DANIEL. As the user scrolls down the page i want the spacing between the letters to expand so it would end up being D A N I E L.
I have seen how to do this with regular text but this will be as I said an SVG logo. I have been searching around buy didn't find anything. Also needs to be mobile friendly. Any tips out there?
This is actually very simple. You just need to watch for scroll events, then update the <text> element based on how far down the page you have scrolled.
I've achieved the letter spacing using the letter-spacing presentation attribute.
window.addEventListener("scroll", function() {
document.getElementById("mytext").setAttribute("letter-spacing", (window.scrollY / window.outerHeight) + "em");
});
body {
height: 2000px;
}
svg {
position: fixed;
}
<svg viewBox="0 0 600 100">
<text id="mytext" x="300" y="70" font-size="50" text-anchor="middle">DANIEL</text>
</svg>
Update
For other non-text elements, like <path> etc, you will need to take a slightly different approah. You'll need to physically move them with a transform.
Here is a quick demo. You'll need to tweak it to get the objects to move where you want them.
var EXPAND_AMOUNT = 40;
window.addEventListener("scroll", function() {
var scrollPercent = window.scrollY / window.outerHeight;
document.getElementById("obj1").setAttribute("transform", "translate("+(scrollPercent * 3 * -EXPAND_AMOUNT)+",0)");
document.getElementById("obj2").setAttribute("transform", "translate("+(scrollPercent * 2 * -EXPAND_AMOUNT)+",0)");
document.getElementById("obj3").setAttribute("transform", "translate("+(scrollPercent * -EXPAND_AMOUNT)+",0)");
document.getElementById("obj4").setAttribute("transform", "translate("+(scrollPercent * EXPAND_AMOUNT)+",0)");
document.getElementById("obj5").setAttribute("transform", "translate("+(scrollPercent * 2 * EXPAND_AMOUNT)+",0)");
document.getElementById("obj6").setAttribute("transform", "translate("+(scrollPercent * 3 * EXPAND_AMOUNT)+",0)");
});
body {
height: 2000px;
}
svg {
position: fixed;
}
<svg viewBox="0 0 600 100">
<rect id="obj1" x="165" y="25" width="40" height="50"/>
<rect id="obj2" x="210" y="25" width="40" height="50"/>
<rect id="obj3" x="255" y="25" width="40" height="50"/>
<rect id="obj4" x="300" y="25" width="40" height="50"/>
<rect id="obj5" x="345" y="25" width="40" height="50"/>
<rect id="obj6" x="390" y="25" width="40" height="50"/>
</svg>

Is it possible to justify SVG text using d3js?

I'm wrapping text using M.Bostock's wrap function but can't find a way to justify it.
Is that even possible in d3 ?
If not, is there a way to "mimic" this kind of text disposition ?
EDIT: Thanks to Logikos suggestion, i've found this example from M.Bostock putting a foreignObject inside svg.
Here is the snippet:
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500);
svg.append("foreignObject")
.attr("width", 480)
.attr("height", 500)
.append("xhtml:body")
.style("font", "14px 'Helvetica Neue'")
.html("<h1>An HTML Foreign Object in SVG</h1><p>Veeery long text");
Then you just need to add in the CSS:
body {text-align: justify;
text-align-last: start;
}
It is not exactly what your looking for but something I used several years ago. Instead of using that function to mimic wrapping you can instead put html inside svg with the foreignObject tag - http://ajaxian.com/archives/foreignobject-hey-youve-got-html-in-my-svg
As html you can style it however you want, text wrapping, justified etc etc.
I have not worked with d3 or SVG's in over 5 years so it is difficult to remember but thought I'd share this in-case it was of any use.
This is the example markup from the link I posted above:
< ?xml version="1.0" standalone="yes"?>
<svg xmlns = "http://www.w3.org/2000/svg">
<rect x="10" y="10" width="100" height="150" fill="gray"/>
<foreignobject x="10" y="10" width="100" height="150">
<body xmlns="http://www.w3.org/1999/xhtml">
<div>Here is a <strong>paragraph</strong> that requires <em>word wrap</em></div>
</body>
</foreignobject>
<circle cx="200" cy="200" r="100" fill="blue" stoke="red"/>
<foreignobject x="120" y="120" width="180" height="180">
<body xmlns="http://www.w3.org/1999/xhtml">
<div>
<ul>
<li><strong>First</strong> item</li>
<li><em>Second</em> item</li>
<li>Thrid item</li>
</ul>
</div>
</body>
</foreignobject>
</svg>
Please note browser support: http://caniuse.com/#search=foreignObject
Which says it will work in everything other than opera mini. Though there are some limitations in IE and Edge:
1 IE11 and below do not support . 2 IE and Edge do not
support applying SVG filter effects to HTML elements using CSS.
You should check it in IE and Edge, in one place the site says it does not support it, in another it says it supports it somewhat...

Image mask in Mozilla + foreignObject + Ajax

http://continent-news.info/page_20.html
In the left column of news, they opens in a popup window, and loaded with Ajax.
<div class="ukraine_mask1">
<svg height="116px" width="142px">
<defs>
<mask id="ukraine_mask1" maskContentUnits="userSpaceOnUse" maskUnits="userSpaceOnUse">
<image xlink:href="mask/ukraine_mask1.png" height="116px" width="142px">
</mask>
</defs>
<foreignObject class="recov_ukraine_mask1" style="mask: url(#ukraine_mask1);" height="100%" width="100%">
<div class="element_mask mask1_ukraine">
<img src="../inf_images/small/7812_8926.jpeg">
</div>
</foreignObject>
</svg>
</div>
problem in Mozilla:
Some news used map with a mask, the first time the mask works well. But if I click another news with mask, they does not want to re-use mask... =( If I press again the first news, it will work.
The second time, does not want to re-use =(
If in firebug disable / apply
mask: url ("# ukraine_mask1")
in
foreignObject class = "recov_ukraine_mask1"
it will work again ...
Maybe someone have an idea how to solve this problem?
I tried to add a simple style in СSS, but does not help = (

SVG frame-based animation

Could anyone suggest what is the best way to implement frame-based animation in svg, based on JPEG's?
One example which I've found is this:
<svg version="1.1" baseProfile="tiny" id="svg-root"
width="100%" height="100%" viewBox="0 0 480 360"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<image width="320" height="240" xlink:href="test1.jpg">
<animate id='frame_0' attributeName='display' values='inline;none'
dur='0.5s' fill='freeze' begin="0s" repeatCount="indefinite"/>
</image>
<image width="320" height="240" xlink:href="test2.jpg">
<animate id='frame_1' attributeName='display' values='none;inline'
dur='0.5s' fill='freeze' begin="0.5s" repeatCount="indefinite" />
</image>
</svg>
It works for 2 frames, but doesn't really scale. I would like to have something which can handle 100 frames and more.
It's much easier:
<svg version="1.1" baseProfile="tiny" id="svg-root"
width="100%" height="100%" viewBox="0 0 480 360"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<image width="320" height="240" xlink:href="test1.jpg">
<animate attributeName="xlink:href"
values="test1.jpg;test2.jpg"
begin="0s" repeatCount="indefinite" dur="1s"/>
</image>
</svg>
An alternative approach,
If your animation is working, but it's just a matter of too much production to get the files setup, you can use a template to generate your SVG.
Use something like Grunt.Js to read all the images in a directory and then, have an underscore template build the SVG frames the way you already have them setup from an array of the filepaths.
These code snippets might not work out of the box, but it's pretty close.
Here the grunt file grabs the files in the folder, check if they're images then pushes them to an array.
// gruntfile.js //
var fs = require('fs');
var path = require('path');
var _ = require("underscore");
grunt.registerTask('Build Animated SVG', function () {
var template = grunt.file.read("/path to SVG underscore template/"); //see SVG section below.
var frames = [];
var pathtoframes = "mypath";
var mySVG = "mysvg.svg";
fs.readdirSync(path.resolve(pathtoframes)).forEach(function (file) {
if (filetype == "svg" || filetype == "png" || filetype == "jpg" || filetype == "gif") {
var frame = {};
frame.src = pathtoframes + "/" + file;
frames.push(frame);
}
});
var compiledSVG = _.template(template, {frames:frames});
grunt.file.write(path.resolve(pathtoframes) + "/compiled_" + mySVG, compiledSVG);
});
This template will get read in by the grunt file, and underscore will loop through each file and write that into a big string. Grunt then saves that out as an SVG that you can load.
<!-- SVG underscore template -->
<svg version="1.1" baseProfile="tiny" id="svg-root"
width="100%" height="100%" viewBox="0 0 480 360"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<% _.each(frames, function(frame, index){ %>
<image width="320" height="240" xlink:href="<%= frame.src %>">
<animate
id='frame_<%= index %>'
attributeName='display'
values='none;inline'
dur='0.5s'
fill='freeze'
begin="0.5s"
repeatCount="indefinite"
/>
</image>
<% } %>
</svg>
https://michaelsboost.github.io/SVGAnimFrames/
You can easily use my library SVGAnimFrames for this. Simply by calling 1 line of code...
SVGAnimFrames("#bounce svg", "repeat", "40", "0");
Refer to the Github repo to learn how to use it.
Ideally your best bet is to use a spritesheet and animate frame by frame with that which minimizes unnecessary http requests.

Resources