Community!
Quite often I found answers to my questions here.
Now I have got one, I couldn't solve so far.
I need to steer an SVG-Object / Links from within its embbeding HTML-file.
Set-Up:
HTML-File
- one div with the SVG-File, linked with an Object-Tag
- another div ontop of it, using z-index, to serve as a menue for the SVG-File.
SVG-File: ist a sozi-presentation (amazing thing, sozi!).
You can change the presentation frames either in html using sozi_file.svg#frame01,....
and also in the object tag "object data="sozi_file.svg#frame01" ..."
I want to put up links like "Frame 02" in the Menue-div to direct the presentation from outside.
How can I target the ? like the link beeing "a ... "sozi_file.svg#frame02" Frame 02 /a
My example can be found here, no working links so far, just the setup: http://noahmed.de/canvas_test/canvas.html
Mark, this starts at frame 2 already "#f02", using mouse buttons, you can click through the presentation.
EDIT: PROBLEM SOLVED
Guillaume, developer of sozi, was so kind to answer this question:
the object tag including the svg.file needs a name-attribut, as to target this ojbect-Tag.
the links need to contain target-attribut, refering to the name-attribut in the ojbect-Tag
the href will be like: svg-file.svg#slide02 and so on.
Amazing!
Thanks for helping!
Paul
I'll take a shot at an answer.. :)
You can place function calls in the object's svg file, where the function itself resides within the parent HTML. Each function call will be preceeded by 'parent', e.g. onclick="parent.myFunction()" The function can create action in either the Object's svg and/or the parent HTML(or other html-resident svg elements, but NOT in another object)
Does this help a bit?
Below is an example. You can paste this into your own htm file. Also make 2 svg files: obj.svg and obj2.svg file. This may not be what you need because you cannot click on a link or function in your html that will interact with svg in the object. Of course, you can change the data value of the object and call a new svg file into the object. This is shown in the link.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title> SVG in Object : parent.functions</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body style='padding:10px;font-family:arial'>
<center>
<h4>SVG in Object : parent.functions</h4>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
SVG within an Object can include function calls that are resident in the parent HTML. These functions can perform actions in either the parent html document and/or within the object.
</div>
<div style='width:400px;height:400px;background-color:lightgreen'>
<object data="obj.svg" type="image/svg+xml" id="objsvg" width="400" height="400"></object><br />
</div><br />
<i>Click on element to turn its fill color to orange</i><br /><br />
<a href=javascript:changeObjData()>Change Object Data</a><br /><br />
<object data="obj.svg" type="image/svg+xml" width="400" height="400"></object>
<br />Javascript:<br />
<textarea id=jsValue style='border-radius:26px;font-size:110%;font-weight:bold;color:midnightblue;padding:16px;background-color:beige;border-width:0px;font-size:100%;font-family:lucida console;width:90%;height:400px'></textarea>
</center>
<div id='browserDiv' style='padding:5px;position:absolute;top:5px;left:5px;background-color:gainsboro;'>OK in:IE11/CH32/FF23<br /></div>
<script id=myScript>
/* obj.svg file
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
<circle onclick="parent.clickMe(evt)" id="myCircle" cx="100" cy="100" fill="blue" r="80" />
<rect onclick="parent.clickMe(evt)" id="myRect" x="200" y="200" fill="red" width="200" height="100" />
</svg>
*/
/* obj2.svg file
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
<circle id="myCircle1" cx="50" cy="100" fill="blue" r="20" />
<circle id="myCircle2" cx="100" cy="50" fill="green" r="20" />
<circle id="myCircle3" cx="300" cy="100" fill="red" r="20" />
<circle id="myCircle4" cx="200" cy="300" fill="orange" r="20" />
</svg>
*/
//---click within circle/rect element in the object---
function clickMe(evt)
{
var target=evt.target
target.setAttribute("fill","orange")
}
//--link---
function changeObjData()
{
objsvg.data="obj2.svg"
}
</script>
<script>
document.addEventListener("onload",init(),false)
function init()
{
jsValue.value=myScript.text
}
</script>
</body>
</html>
Related
I have created 360 vr image with a few hotspots using a-frame.
Now I am trying to add the zoom fade transition like google street view for the hotspot changing image, but I've looking all over internet and tried a dozen times failing, so I need your help.
(**P.s. I am not a code developer, which means I am super newbie, so u might need to treat me like a idiot/baby to guide me.)
document.querySelector('#here1').addEventListener('click', function () {
document.querySelector('#pano').setAttribute('src','#pano1');
document.querySelector('#here1').setAttribute('visible','false');
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Kempas Residence</title>
<meta name="description" content="360° Image - A-Frame" />
<script src="https://aframe.io/aframe/dist/aframe-master.min.js"></script>
</head>
<body>
<a-scene cursor="rayOrigin: mouse">
<a-assets>
<audio id="click-sound" src="https://cdn.aframe.io/360-image-gallery-boilerplate/audio/click.ogg"></audio>
<img id="pano1" src="https://cdn.glitch.com/6128c6fd-5c0c-424e-823f-27840db2dfcb%2Fpano2.jpg?v=1590040717497"/>
<img id="pano2" src="https://cdn.glitch.com/6128c6fd-5c0c-424e-823f-27840db2dfcb%2Fpano1.jpg?v=1590040608692"/>
</a-assets>
<a-sky src="#pano2" id="pano" rotation="0 -85 0"></a-sky>
<a-camera id="camera" drag-look-controls reverse-mouse-drag="true" visible="false" zoom="1">
<a-cursor id="cursor">
<a-animation begin="click" easing="ease-in" attribute="scale" fill="backwards" from="0.1 0.1 0.1" to="1 1 1" dur="150"></a-animation>
<a-animation begin="cursor-fusing" easing="ease-in" attribute="scale" from="1 1 1" to="0.1 0.1 0.1" dur="1500"></a-animation>
</a-cursor>
</a-camera>
<a-octahedron id="here1" position="23 4 -0.95" scale="-0.5 1 -0.5" opacity="1" animation="property: position; dir: alternate; from: 23 4 -0.95; to: 23 5 -0.95; dur: 750; loop: true" color="#00E4FF"></a-octahedron>
</a-scene>
</body>
I'm using ng2-charts to make line charts in my Angular 8 application. But, the line charts are being displayed as curved lines and not straight lines. I'm taking the code from the following link https://valor-software.com/ng2-charts/#/LineChart as you can see, the lines are not straight. How to make them straight lines?
Thanks.
Pass in bezierCurve: false into the options like this:
<canvas baseChart width="400" height="400"
[datasets]="lineChartData"
[labels]="lineChartLabels"
[options]="{bezierCurve: false}">
</canvas>
Or if you use the newer version lineTension: 0:
<canvas baseChart width="400" height="400"
[datasets]="lineChartData"
[labels]="lineChartLabels"
[options]="{lineTension: 0}">
</canvas>
Or if you want to affect a certain dataset:
<canvas baseChart width="400" height="400"
[datasets]="{data: data, lineTension: 0}"
[labels]="lineChartLabels"
[options]="lineChartOptions">
</canvas>
Unrelated question from OP:
I noticed that by default the area under the line graph has a color, I tried background-color:'none'; but that didn't work and it just put a grey color under it. Is there any way to not have any color under the line?
<canvas baseChart width="400" height="400"
[datasets]="{data: data, lineTension: 0, fill: false}"
[labels]="lineChartLabels"
[options]="lineChartOptions">
</canvas>
[datasets]="{fill: false}"
New version of ng2-chart are in this way:
Javascript Code:
public lineChartOptions: ChartConfiguration['options'] = {
elements: {
line: {
tension: 0
}
}
}
HTML Code:
<canvas baseChart
[data]="lineChartData"
[options]="lineChartOptions">
</canvas>
I have several SVG graphics I'd like to modify the colors of via my external style sheets - not directly within each SVG file. I'm not putting the graphics in-line, but storing them in my images folder and pointing to them.
I have implemented them in this way to allow tooltips to work, and I also wrapped each in an <a> tag to allow a link.
<a href='http://youtube.com/...' target='_blank'><img class='socIcon' src='images/socYouTube.svg' title='View my videos on YouTube' alt='YouTube' /></a>
And here is the code of the SVG graphic:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="stylesheets/main.css" type="text/css"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
<g>
<path d="M28.44......./>
</g>
</svg>
I put the following in my external CSS file (main.css):
.socIcon g {fill:red;}
Yet it has no effect on the graphic. I also tried .socIcon g path {} and .socIcon path {}.
Something isn't right, perhaps my implementation doesn't allow external CSS modifications, or I missed a step? I'd really appreciate your help! I just need the ability to modify the colors of the SVG graphic via my external stylesheet, but I cannot lose the tooltip and link ability (I may be able to live without tooltips though).
Your main.css file would only have an effect on the content of the SVG if the SVG file is included inline in the HTML:
https://developer.mozilla.org/en/docs/SVG_In_HTML_Introduction
<html>
<body>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
<g>
<path d="M28.44......."/>
</g>
</svg>
</html>
If you want to keep your SVG in files, the CSS needs to be defined inside of the SVG file.
You can do it with a style tag:
http://www.w3.org/TR/SVG/styling.html#StyleElementExample
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="50px" height="50px" viewBox="0 0 50 50">
<defs>
<style type="text/css"><![CDATA[
.socIcon g {
fill:red;
}
]]></style>
</defs>
<g>
<path d="M28.44......./>
</g>
</svg>
You could use a tool on the server side to update the style tag depending on the active style. In ruby you could achieve this with Nokogiri. SVG is just XML. So there are probably many XML libraries available that can probably achieve this.
If you're not able to do that, you will have to just have to use them as though they were PNGs; creating a set for each style, and saving their styles inline.
You can do what you want, with one (important) caveat: the paths within your symbol can't be styled independently via external CSS -- you can only set the properties for the entire symbol with this method. So, if you have two paths in your symbol and want them to have different fill colors, this won't work, but if you want all your paths to be the same, this should work.
In your html file, you want something like this:
<style>
.fill-red { fill: red; }
.fill-blue { fill: blue; }
</style>
<a href="//www.example.com/">
<svg class="fill-red">
<use xlink:href="images/icons.svg#example"></use>
</svg>
</a>
And in the external SVG file you want something like this:
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="example" viewBox="0 0 256 256">
<path d="M120...." />
</symbol>
</svg>
Swap the class on the svg tag (in your html) from fill-red to fill-blue and ta-da... you have blue instead of red.
You can partially get around the limitation of being able to target the paths separately with external CSS by mixing and matching the external CSS with some in-line CSS on specific paths, since the in-line CSS will take precedence. This approach would work if you're doing something like a white icon against a colored background, where you want to change the color of the background via the external CSS but the icon itself is always white (or vice-versa). So, with the same HTML as before and something like this svg code, you'll get you a red background and a white foreground path:
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="example" viewBox="0 0 256 256">
<path class="background" d="M120..." />
<path class="icon" style="fill: white;" d="M20..." />
</symbol>
</svg>
You can include in your SVG files link to external css file using:
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="mystyles.css" type="text/css"/>
You need to put this after opening tag:
<svg>
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="mystyles.css" type="text/css"/>
<g>
<path d=.../>
</g>
</svg>
It's not perfect solution, because you have to modify svg files, but you modify them once and than all styling changes can be done in one css file for all svg files.
It is possible to style an SVG by dynamically creating a style element in JavaScript and appending it to the SVG element. Hacky, but it works.
<object id="dynamic-svg" type="image/svg+xml" data="your-svg.svg">
Your browser does not support SVG
</object>
<script>
var svgHolder = document.querySelector('object#dynamic-svg');
svgHolder.onload = function () {
var svgDocument = svgHolder.contentDocument;
var style = svgDocument.createElementNS("http://www.w3.org/2000/svg", "style");
// Now (ab)use the #import directive to load make the browser load our css
style.textContent = '#import url("/css/your-dynamic-css.css");';
var svgElem = svgDocument.querySelector('svg');
svgElem.insertBefore(style, svgElem.firstChild);
};
</script>
You could generate the JavaScript dynamically in PHP if you want to - the fact that this is possible in JavaScript opens a myriad of possibilities.
One approach you can take is just to use CSS filters to change the appearance of the SVG graphics in the browser.
For example, if you have an SVG graphic that uses a fill color of red within the SVG code, you can turn it purple with a hue-rotate setting of 180 degrees:
#theIdOfTheImgTagWithTheSVGInIt {
filter: hue-rotate(180deg);
-webkit-filter: hue-rotate(180deg);
-moz-filter: hue-rotate(180deg);
-o-filter: hue-rotate(180deg);
-ms-filter: hue-rotate(180deg);
}
Experiment with other hue-rotate settings to find the colors you want.
To be clear, the above CSS goes in the CSS that is applied to your HTML document. You are styling the img tag in the HTML code, not styling the code of the SVG.
And note that this won’t work with graphics that have a fill of black or white or gray. You have to have an actual color in there to rotate the hue of that color.
It should be possible to do by first inlining the external svg images. The code below comes from replace all SVG images with inline SVG by Jess Frazelle.
$('img.svg').each(function(){
var $img = $(this);
var imgID = $img.attr('id');
var imgClass = $img.attr('class');
var imgURL = $img.attr('src');
$.get(imgURL, function(data) {
// Get the SVG tag, ignore the rest
var $svg = $(data).find('svg');
// Add replaced image's ID to the new SVG
if (typeof imgID !== 'undefined') {
$svg = $svg.attr('id', imgID);
}
// Add replaced image's classes to the new SVG
if (typeof imgClass !== 'undefined') {
$svg = $svg.attr('class', imgClass+' replaced-svg');
}
// Remove any invalid XML tags as per http:validator.w3.org
$svg = $svg.removeAttr('xmlns:a');
// Replace image with new SVG
$img.replaceWith($svg);
});
});
A very quick solution to have dynamic style with an external css stylesheet, in case you are using the <object> tag to embed your svg.
This example will add a class to the root <svg> tag on click on a parent element.
file.svg :
<?xml-stylesheet type="text/css" href="../svg.css"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="">
<g>
<path/>
</g>
</svg>
html :
<a class="parent">
<object data="file.svg"></object>
</a>
Jquery :
$(function() {
$(document).on('click', '.parent', function(){
$(this).find('object').contents().find('svg').attr("class","selected");
}
});
on click parent element :
<svg xmlns="http://www.w3.org/2000/svg" viewBox="" class="selected">
then you can manage your css
svg.css :
path {
fill:none;
stroke:#000;
stroke-miterlimit:1.41;
stroke-width:0.7px;
}
.selected path {
fill:none;
stroke:rgb(64, 136, 209);
stroke-miterlimit:1.41;
stroke-width:0.7px;
}
For External styles
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
<style>
#import url(main.css);
</style>
<g>
<path d="M28.44......./>
</g>
</svg>
For Internal Styles
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
<style>
.socIcon g {fill:red;}
</style>
<g>
<path d="M28.44......./>
</g>
</svg>
Note: External Styles will not work if you include SVG inside <img> tag. It will work perfectly inside <div> tag
When used in an <image> tag SVG must be contained in a single file for privacy reasons. This bugzilla bug has more details on exactly why this is so. Unfortunately you can't use a different tag such as an <iframe> because that won't work as a link so you'll have to embed the CSS in a <style> tag within the file itself.
One other way to do this would be to have the SVG data within the main html file i.e.
<a href='http://youtube.com/...' target='_blank'>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
<g>
<path d="M28.44......./>
</g>
</svg>
</a>
You could style that with an external CSS file using the HTML <link> tag.
What works for me: style tag with #import rule
<defs>
<style type="text/css">
#import url("svg-common.css");
</style>
</defs>
#leo here is the angularJS version, thanks again
G.directive ( 'imgInlineSvg', function () {
return {
restrict : 'C',
scope : true,
link : function ( scope, elem, attrs ) {
if ( attrs.src ) {
$ ( attrs ).each ( function () {
var imgID = attrs.class;
var imgClass = attrs.class;
var imgURL = attrs.src;
$.get ( imgURL, function ( data ) {
var $svg = $ ( data ).find ( 'svg' );
if ( typeof imgID !== 'undefined' ) {
$svg = $svg.attr ( 'id', imgID );
}
if ( typeof imgClass !== 'undefined' ) {
$svg = $svg.attr ( 'class', imgClass + ' replaced-svg' );
}
$svg = $svg.removeAttr ( 'xmlns:a' );
elem.replaceWith ( $svg );
} );
} );
}
}
}
} );
In my case, I have applied display:block in outer class.
Need to experiment, where it fits.
Inside inline svg adding class and style does not even remove the above white-space.
See: where the display:block gets applied.
<div class="col-3 col-sm-3 col-md-2 front-tpcard"><a class="noDecoration" href="#">
<img class="img-thumbnail img-fluid"><svg id="Layer_1"></svg>
<p class="cardtxt">Text</p>
</a>
</div>
The class applied
.front-tpcard .img-thumbnail{
display: block; /*To hide the blank whitespace in svg*/
}
This worked for me.
Inner svg class did not worked
I know its an old post, but just to clear this problem... you're just using your classes at the wrong place :D
First of all you could use
svg { fill: red; }
in your main.css to get it red. This does have effect. You could probably use node selectors as well to get specific paths.
Second thing is, you declared the class to the img-tag.
<img class='socIcon'....
You actually should declare it inside your SVG. if you have different paths you could define more of course.
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="stylesheets/main.css" type="text/css"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
<g>
<path class="myClassForMyPath" d="M28.44......./>
</g>
</svg>
Now you could change the color in your main.css like
.myClassForMyPath {
fill: yellow;
}
As described in answers here and in other related questions, stylesheets only apply to the current DOM. As such, you need to make the svg part of the document's DOM, by inlining it inside the html, or including it inside the DOM using javascript.
That's what I ended up doing there:
<object type="image/svg+xml" data="illustration.svg"
onload="this.parentNode.replaceChild(this.contentDocument.documentElement, this);">
</object>
While that solution works really well for me, only use it on documents you control, as inline loading an svg from an untrusted source gives that source the ability to include at least arbitrary scripts, css and other elements inside your HTML, breaking the sandbox.
I haven't investigated how well caching works with this, but it should work as well as with img tags, given that the javascript function is ran after the element loads. Feel free to edit this.
If javascript is disabled, the svg is not included into the DOM, and the style is not applied, so make sure the default style is usable. CSS custom properties (variables) with fallbacks work quite well for that use-case.
Not fully tested yet, but Ive found a nice way to treat external svg files like inlines. No Javascript, no server-code - just a document root-id:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" id="svgroot">...
After this we're allowed to use it with an SVG2-Tag which seems to be supported by Chrome/Edge - Blink; Firefox - Gecko; Safari - Webkit:
<html>
<head>
<style>
.primary-text {
color: green;
}
.icon {
height: 100px;
width: 100px;
fill: currentColor;
}
</style>
</head>
<body>
<h3>svg Fill currentColor</h3>
<svg class="primary-text icon">
<use href="example.svg#svgroot"></use>
</svg>
</body>
</html>
Going further, you're able to create a resource-dictionary/sprite file:
<svg xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 512 512" id="apple">...
<svg viewBox="0 0 512 512" id="peach">...
</svg>
Honestly, this seems too good to be true... :D
// Edit:
This seems to be a well respected approach:
https://icons.getbootstrap.com/#usage
"I am actually going to change the colors of these images based on what color scheme the user has chosen for my site." - Jordan 10 hours ago
I suggest you to use PHP for this. There's really no better way to do this without icon fonts, and if you resist using them, you could try this:
<?php
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" encoding="utf-8"?>';
$color = $_GET['color'];
?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 56.69 56.69">
<g>
<path fill="<?php echo $color; ?>" d="M28.44..."/>
</g>
</svg>
And later you could use this file as filename.php?color=#ffffff to get the svg file in the desired color.
This method will work if the svg is viewed within a web browser but as soon as this code is uploaded to the sever and the class for the svg icon is coded as if it was a background image the color is lost and back to the default color. Seems like the color can not be changed from the external style sheet even though both the svg class for the color and the top layer class for the display and position of the svg are both mapped to the same directory.
I have an issue using polymer (1.3.1) to define a custom element which is a svg button for a Portal webapp.
Here the code of my custom element :
<link rel="import" href="../../lib/polymer/1.3.1/polymer.html">
<dom-module id="portal-button">
<link rel="import" type="css" href="portal-button.css">
<template>
<svg id="hexagon-button" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="187">
<a xlink:href="#dummy" xlink:href$="{{url}}">
<defs>
<pattern id="dashed-line" height="9" width="9" patternUnits="userSpaceOnUse">
<rect x="0" y="0" width="9" height="9" fill="rgb(245,245,245)" />
<line x1="1" y1="9" x2="9" y2="1" stroke="rgb(187,187,187)" stroke-dasharray="2" />
</pattern>
<pattern id="logo" width="100%" height="100%" viewBox="0 0 135 133">
<image id="buttonlogo" width="135" height="133" xlink:href="#dummy" xlink:href$="{{src}}" />
</pattern>
<pattern id="text" width="100%" height="100%" viewBox="0 0 590 76">
<image id="buttontext" width="590" height="76" xlink:href="#dummy" xlink:href$="{{text}}" />
</pattern>
</defs>
<g class="button">
<g class="back">
<path d="M 150,13 L 50,13 0,100 50,187 150,187 200,100 z M 140,31 L 60,31 20,100 60,169 140,169 180,100 z" fill-rule="evenodd" fill="url(#dashed-line)" />
<polygon points="140,31 60,31 20,100 60,169 140,169 180,100" fill="rgb(88,151,162)" />
<polygon points="140,31 60,31 20,100 60,169 140,169 180,100" fill="url(#logo)" />
</g>
<g class="front">
<polygon points="19,100 25,90 175,90 181,100 175,110 25,110" fill="url(#dashed-line)" />
<polygon points="19,100 25,90 175,90 181,100 175,110 25,110" fill="url(#text)" />
</g>
</g>
</a>
</svg>
</template>
</dom-module>
<script>
Polymer({
is: 'portal-button',
properties: {
text: String,
url: String,
src: String
}
});
</script>
A little bit of css to display/hide the front svg element
.back {
fill-opacity: 0.5;
}
.front {
fill-opacity: 0.1;
}
.button:hover > * {
fill-opacity: 1;
}
The index.html with declaration of two instances of my custom element
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Izakiel's Lair</title>
<link rel="icon" href="chaos_symbol.png">
<!-- include polymer html5 polyfill library -->
<script src="lib/webcomponentsjs/0.7.21/webcomponents-lite.js"></script>
<link rel="import" href="components/portal-button/portal-button.html">
</head>
<body>
<portal-button id="virtualmin" url="http://localhost:8080/portal" src="img/virtualmin-logo.svg" text="img/virtualmin-titles.svg"></portal-button>
<portal-button id="jenkins" url="http://localhost:8080/portal" src="img/jenkins-logo.svg" text="img/jenkins-titles.svg"></portal-button>
</body>
</html>
When the page is loaded the rendering is perfectly ok.
When i hover with cursor on a button, the opacity is set to 1 by css, forcing the browser to redraw the button.
When the button is re-rendered, all the information for svg image are rendered with the latest declared element (i.e the jenkins button data in this example) but ll the datas in the DOM are perfectly goods that is weird in my opinion.
Does someone know why the browser set all custom elements rendering with latest element rendering or is it a bug ?
My previous test was done with Chrome, when i try with Firefox it's even worst, all the elements have the rendering of the first element, but datas in the DOM are good. Did i miss something ?
I think your issue is that the patterns are global, not scoped to the shadow root. I tried this with both shady DOM and native shadow root, with the same results.
Here's a partial workaround that fixes the immediate issue on both Chrome and Firefox: create a unique ID for each pattern:
<pattern id="logo-{{id}}" width="100%" height="100%" viewBox="0 0 135 133">
<image id="buttonlogo" width="135" height="133" xlink:href="#dummy" xlink:href$="{{src}}" />
</pattern>
Apply the pattern like this:
<polygon points="140,31 60,31 20,100 60,169 140,169 180,100" fill$="[[_computeFill('#logo', id)]]" />
I found I needed a computed binding here--I think the parens in the url( arg mixed up the binding system, but perhaps I just got something wrong. YMMV. Anyway, the computing function could look like this:
_computeFill: function(name, id) {
return 'url('+ name + '-' + id + ')';
}
You could make this a little more elegant, but this should get you working.
This is a partial workaround because if you re-use an ID, you'll be back to the initial problem of swapping images.
If you wanted to avoid that, you could define a separate library of patterns, identified by ID (like the iron-iconset-svg does for icons). Or as a simpler solution, you could compute a unique ID from the SVG file name.
Hope this helps.
When an SVG is directly included in a document using the <svg> tag, you can apply CSS styles to the SVG via the document's stylesheet. However, I am trying to apply a style to an SVG which is embedded (using the <object> tag).
Is it possible to use anything such as the following code?
object svg {
fill: #fff;
}
Short answer: no, since styles don't apply across document boundaries.
However, since you have an <object> tag you can insert the stylesheet into the svg document using script.
Something like this, and note that this code assumes that the <object> has loaded fully:
var svgDoc = yourObjectElement.contentDocument;
var styleElement = svgDoc.createElementNS("http://www.w3.org/2000/svg", "style");
styleElement.textContent = "svg { fill: #fff }"; // add whatever you need here
svgDoc.getElementById("where-to-insert").appendChild(styleElement);
It's also possible to insert a <link> element to reference an external stylesheet:
var svgDoc = yourObjectElement.contentDocument;
var linkElm = svgDoc.createElementNS("http://www.w3.org/1999/xhtml", "link");
linkElm.setAttribute("href", "my-style.css");
linkElm.setAttribute("type", "text/css");
linkElm.setAttribute("rel", "stylesheet");
svgDoc.getElementById("where-to-insert").appendChild(linkElm);
Yet another option is to use the first method, to insert a style element, and then add an #import rule, e.g styleElement.textContent = "#import url(my-style.css)".
Of course you can directly link to the stylesheet from the svg file too, without doing any scripting. Either of the following should work:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="my-style.css" type="text/css"?>
<svg xmlns="http://www.w3.org/2000/svg">
... rest of document here ...
</svg>
or:
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<link href="my-style.css" type="text/css" rel="stylesheet"
xmlns="http://www.w3.org/1999/xhtml"/>
</defs>
... rest of document here ...
</svg>
Update 2015: you can use jquery-svg plugin for apply js scripts and css styles to an embedded SVG.
You can do this without javsscrpt by putting a style block with your styles inside the SVG file itself.
<style type="text/css">
path,
circle,
polygon {
fill: #fff;
}
</style>
If the only reason for using the tag to inlcude the SVG is that you do not want to clutter your source code with the markup from the SVG, you should take a look at SVG injectors like SVGInject.
SVG injection uses Javascript to inject an SVG file inline into your HTML document. This allows for clean HTML source code while making the SVGs fully styleable with CSS. A basic example looks like this:
<html>
<head>
<script src="svg-inject.min.js"></script>
</head>
<body>
<img src="image.svg" onload="SVGInject(this)" />
</body>
</html>
Based on #Erik Dahlström answer, found a short path as follow:
let svg_objecst = document.getElementsByClassName('svg-object')
const forceStylingObjSvg = (svg)=>{
var svgDoc = svg.contentDocument;
svgDoc.firstElementChild.setAttribute('fill','blue')
}
Array.from(svg_objecst).forEach((obj)=>{
obj.addEventListener('load',()=>forceStylingObjSvg(obj))
})
You can create a custom element to inject the SVG file into your html.
This way, the SVG will be inlined, and you can easily apply styles using CSS.
This custom element will work just like the <object> or <embed> tags. The only difference is that <object> or <embed> tags injects the data in a shadow root, which prevents styling from the parent document, while <custom-svg> injects the data in the document itself.
I have tried too many ways to style my SVG images, and this was the easiest and more flexible way i have found so far.
<html>
<head>
<style>
.blue {
fill: blue;
}
.red {
fill: red;
}
</style>
</head>
<body>
<custom-svg class="blue" src="icon.svg"></custom-svg>
<custom-svg class="red" src="icon.svg"></custom-svg>
<script>
class CustomSVG extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
fetch(this.getAttribute('src'))
.then(response => response.text())
.then(text => {
this.innerHTML = text;
});
}
}
customElements.define('custom-svg', CustomSVG);
</script>
</body>
</html>
Notes
The SVG image must not have the "fill" attribute if you want, for example, change the fill color using CSS.
custom-svg works very good, for width style use this:
custom-svg svg{
max-width:64px;
max-height:64px;
}