I'm aware that there are plenty of methods to use SVG sprites in HTML. My preference to this date has been to use something like
<div class="container">
<svg class="icon">
<title>Icon Title</title>
<use xlink:href="/svg/sprite.svg#icon"/>
</svg>
</div>
However, now I wanted to load the sprite from a subdomain, like this:
<div class="container">
<svg class="icon">
<title>Icon Title</title>
<use xlink:href="https://sub.domain.com/svg/sprite-home.svg#icon"/>
</svg>
</div>
Unfortunately, this doesn't work as the file is not fetched. I've tried with <object> as well, but that doesn't seem to work either.
So far, I'm only able to use
<?php include_once("https://sub.domain.com/svg/sprite.svg"); ?>
It's ok as a quick fix, as this doesn't involve much refactoring. However, this also means the HTML gets bloated.
With the <use> method the sprite gets cached. But with the include method the sprite isn't cached, only gets embedded, and so it is far from ideal.
Does anybody use any alternative to the php include method that is compatible with cross domain requests and browser caching?
Thanks to this post at css-tricks I've been able to work out how to do this. The idea is to AJAX to bring the SVG sprite with jQuery like this (see post for vanilla version):
$j.get("https://sub.domain.com/svg/sprite-home.svg", function(data) {
var div = document.createElement("div");
div.className = 'no-display';
div.innerHTML = new XMLSerializer().serializeToString(data.documentElement);
document.body.insertBefore(div, document.body.childNodes[0]);
});
What this does is insert the SVG at the beginning of the document. Unlike the original post, I've added a class to make it hidden, as otherwise you get a blank big space at the top in Chrome. The result is great (it works with local files too) and now you can reference icons by just their id.
<div class="container">
<svg class="icon">
<title>Icon Title</title>
<use xlink:href="#icon"/>
</svg>
</div>
There are many advantages to this technique:
SVG sprite is cached
Really simple to use as you only reference the icon
You can request several SVG sprites and they all work the same
The only thing to bear in mind is that, this requires CORS AJAX to be set up. For those using nginx, it would be simple enough:
location ~* \.svg$ {
...
add_header 'Access-Control-Allow-Methods' 'GET';
add_header 'Access-Control-Allow-Origin' 'https://your.domain.com';
}
My idea is to inject inline SVG to my HTML using template literals.
The purpose is simply use benefits of styling inline SVG icons with CSS but avoid bloating html code with SVG stuff. Also it's very easy to reuse repeating icons by just adding corresponding class. Also all icons or vector stuff like logo can be stored in single JS file. I know, that's hacky weird idea, but I found it's useful for my project.
So the problem is that my script won't work in browser from my local files.
But it works well in CodePen and JSFiddle.
Local file restrictions are disabled, JS is enabled.
Also any ideas how to optimize it and make it work better are welcome.
var iconLogo = document.querySelectorAll(".ric-logo");
var i;
for (i = 0; i < iconLogo.length; i++) {
iconLogo[i].innerHTML = `
<svg width="120px" height="18px" viewBox="0 0 120 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="ric-logo" stroke="none" stroke-width="1" fill="black" fill-rule="evenodd">
<path d="M23.326087,0 C23.2252174,0 23.1275,0 23.0266304,0 L23.0266304,0 L2.52173913,0 C1.12902107,-8.82200545e-17 1.70558772e-16,1.16795283 0,2.60869565 L0,15 L5.04347826,15 L5.04347826,5.2173913 C5.04347826,4.8572056 5.32573353,4.56521739 5.67391304,4.56521739 L22.9730435,4.56521739 C23.631932,4.55997742 24.1901947,5.0660023 24.2717391,5.7423913 C24.306535,6.10977596 24.1892199,6.47520901 23.948885,6.74807191 C23.7085502,7.02093481 23.3677046,7.17567223 23.0108696,7.17391304 L7.56521739,7.17391304 L7.56521739,11.7391304 L23.0266304,11.7391304 L23.0266304,11.7391304 C23.1275,11.7391304 23.2252174,11.7391304 23.326087,11.7391304 C26.4597026,11.7391304 29,9.11123658 29,5.86956522 C29,2.62789386 26.4597026,1.98495123e-16 23.326087,0 Z" id="Path"></path>
<path d="M64.9565217,1.21154527e-06 L61.173913,1.21154527e-06 C60.170401,-0.000815107822 59.2077021,0.410915432 58.4977174,1.14456624 L49.8796739,10.0532605 C49.6430123,10.2978107 49.3221127,10.4350542 48.9876087,10.4347821 L46.673913,10.4347821 C46.3257335,10.4347821 46.0434783,10.142794 46.0434783,9.78260833 L46.0434783,1.21154527e-06 L41,0 L41,12.3913036 C41,13.8320462 42.1290211,14.9999988 43.5217391,14.9999988 L49.826087,14.9999988 C50.829599,15.0008151 51.7922979,14.5890846 52.5022826,13.8554338 L61.1108696,4.95000041 C61.3493224,4.70184137 61.674158,4.56319679 62.0123913,4.56521787 L64.326087,4.56521787 C64.6742665,4.56521787 64.9565217,4.85720602 64.9565217,5.21739167 L64.9565217,14.9999988 L70,15 L70,2.60869644 C70,1.16795385 68.8709789,1.21154527e-06 67.4782609,1.21154527e-06 L64.9565217,1.21154527e-06 Z" id="Path"></path>
<path d="M114,10 L120,10 L120,16 C120,17.1045695 118.992641,18 117.75,18 L114,18 L114,10 Z" id="Path"></path>
<path d="M106,0 L106,9.7826087 C106,10.1427944 105.720178,10.4347826 105.375,10.4347826 L87.625,10.4347826 C87.279822,10.4347826 87,10.1427944 87,9.7826087 L87,0 L82,0 L82,12.3913043 C82,13.8320472 83.1192881,15 84.5,15 L108.5,15 C109.880712,15 111,13.8320472 111,12.3913043 L111,0 L106,0 Z" id="Path"></path>
</g>
</svg>
`;
}
/* Styling all instances of SVG */
.ric-logo * {
fill: blue;
width: 120px;
height: 15px;
};
<body>
<header class="header-menu">
<div class="ric-logo">
</div>
<div class="menu-content">
<ul>
<li>Item-1</li>
<li>Item-2</li>
<li>Item-3</li>
<li>Item-4</li>
</ul>
</div>
</header>
<main>
<!-- Test repeating SVG class -->
<div class="ric-logo">
</div>
</main>
<footer></footer>
</body>
I'm not sure how you've structured your files, so I might not be reproducing your problems correctly. Let me know if I've made any false assumptions.
Firstly, codepen and the snippets on Stack Overflow automatically include CSS and JS, while local files do not. If you haven't already, you need to include appropriate <script> and <style> tags containing your css and your js.
If you are already doing that and you've just edited them out for the purposes of this question, then another possible problem is that the javascript you've provided you've included at the top of your page. document.querySelectorAll(".ric-logo") won't work until the page has been loaded, and if you put the javascript you've supplied at the top of your page, it will run before the page has finished loading. The easiest way to fix this is to put the javascript at the bottom of your page.
If for some reason you don't want your javascript at the bottom of your page, you need something like jQuery's $(document).ready, or one of the vanilla alternatives from this question.
#Nicholas was right, and the problem was that document.querySelectorAll not working until all the DOM stuff loaded.
So one solution is to place document.querySelectorAll to the bottom of the page.
Another is to use function that run your scripts when pages is loaded. It's explained here.
I applied it to my script and it works well. So if you interested I post the snipped here. It may be helpful for templating using string literals or like in my case dynamically inject Inline SVG.
// Icons SVG injection
// Function that run code when DOM is loaded
function ready(callback){
// in case the document is already rendered
if (document.readyState!='loading') callback();
// modern browsers
else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
if (document.readyState=='complete') callback();
});
}
ready(function(){
// All inside tht function executes when DOM is loaded
// Logo SVG
var mySvg = document.querySelectorAll(".my-svg");
var i;
for (i = 0; i < mySvg.length; i++) {
mySvg[i].innerHTML = `
<svg width="188px" height="188px" viewBox="0 0 188 188" version="1.1">
<circle id="Oval" fill="#FC4903" cx="94" cy="94" r="94"></circle>
</svg>
`
};
});
/* styling svg */
.my-svg * {
fill: red;
width: 200px;
height: 200px;
};
<!-- creating container where you like to insert SVG -->
<div class="my-svg">
<div></div>
</div>
I'm reviewing the code of the visualization here http://bl.ocks.org/mbostock/4062045, and I'm curious to know why is name from the json file not rendered together with the nodes even though the code included:
node.append("title").text(function(d) { return d.name; });
The SVG <title> element is not displayed on screen. It is used as the tooltip text by browsers (and is also used by screen readers) in the same way as a title attribute in HTML.
I.e., the SVG code
<svg>
<image xlink:href="image.png">
<title>My PNG</title>
</image>
</svg>
Is equivalent to the HTML code
<div>
<img src="image.png" title="My PNG" />
</div>
Attribute title is supposed to be displayed as a tooltip (if you hover over a node), and it is really correctly displayed, check it out. (I know... it's not logical, but such is standard)
I am a rookie web developer and I am looking to put data points over an image that can be interacted with when hovered over, similar to most common map applications.
From my current understanding, using the Canvas in Javascript seems to be the best way to go, does anyone have any recommendations on how to do this and maybe point me in the right direction?
Does not require canvas although canvas can be used.
Shortest coding would be make a div with a background image being the image you want to place points on.
If it is not an image then you would need to make two divides on the overlay divide (the first one in the HTML code) use position:absolute to place it on top with the same width and height -- then the image content divide that follows will be layered under your absolute positioned divide.
<div style="background:url(image.jpg); width:100px; height:100px">
... material here is on top of the image ...
</div>
or
<div style="position:absolute; width:100px; height:100px">
... material here is on top of the image ...
</div>
<div style="width:100px; height:100px">
... place object here which picks up your map or whatever ...
</div>
The ... material here is on top of the image ... can be a canvas but SVG would be less coding as it has links supported
<div style="background:url(image.jpg); width:100px; height:100px">
<object data="yourOverlay.svg" width="100" height="100" >
</object>
</div>
Here is a sample SVG file posted at http://tutorials.jenkov.com/svg/a-element.html
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<a xlink:href="/svg/index.html">
<text x="10" y="20">/svg/index.html</text>
</a>
<a xlink:href="/svg/index.html" xlink:show="new">
<text x="10" y="40">/svg/index.html
(xlink:show="new")</text>
</a>
<a xlink:href="/svg/index.html" xlink:show="replace">
<text x="10" y="60">/svg/index.html
(xlink:show="replace")</text>
</a>
<a xlink:href="/svg/index.html" target="_blank">
<text x="10" y="80">m/svg/index.html
(target="_blank")</text>
</a>
<a xlink:href="/svg/index.html" target="_top">
<text x="10" y="100">/svg/index.html
(target="_top")</text>
</a>
</svg>
Depending on your application you may want to consider straight HTML for "... material here is on top of the image ..." so it will work in older browsers.
And FYI you could code the background into the SVG and just have a object tag in the html page and use googles "SVGWEB" http://code.google.com/p/svgweb/ to support nearly every browser.
Good resource here: http://dev.opera.com/articles/view/html5-canvas-painting/
But for what you're doing, you don't really need a canvas, imo. If you have an image, and you know where stuff is that you want to overlay (pixel offset), you can provide the pixel offsets from each data point in JSON or XML to your client script, and then just have it use absolute positioning to place them where they need to be on the image.
Another possible solution is to just use an SVG image which i believe supports links ect directly
I need to have a tooltip show up on mouseover of an SVG Text element. Everything I find on the net says to add a Title element as the first child of the SVG element. It works in Chrome, but not in Safari which is the primary browser of my user base.
Here is simplified example showing my situation. The
is a FontAwesome lightbulb icon that is the element I want the user to mouseover and have the tooltip come up on.
<svg ...><text><title>some text</title></text></svg>
Ideas?
I tested the following snippet in Safari 12.1 and the tooltop "some text" showed up as expected. Perhaps you are testing with an older version of Safari, or maybe you are using a plugin that is affecting this feature?
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css">
<svg width="50" height="50">
<text x="10" y="20" class="fas">
<title>some text</title>
</text>
</svg>