Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG Won't show until I edit the element in Chrome developer tools

Tags:

svg

I'm creating a dom structure which includes an SVG element:

<div data-bind="with: searchable_select.f0000001" style="verticalAlign: top">
  <input data-bind="value: select_filter_value, valueUpdate: 'afterkeydown', event: { change: change_filter_, blur: blur_filter_ }" style="display: none">
  <div>
    <select data-bind="options: select_list, value: working_value, event: { change: change_selector_ }, optionsText: 'label', optionsValue: 'value'" style="display: inline-block; maxWidth: 150px">
      <option value="person_full_name_asc">Member Full Name (A-Z)</option>
      <option value="person_full_name_desc">Member Full Name (Z-A)</option>
    </select>
    <svg style="display: inline-block; verticalAlign: middle" width="18" height="18" xmlns="http://www.w3.org/2000/svg" version="1.1">
      <g>
        <circle cx="6" cy="6" r="5" fill="#AAAAAA" stroke="#000000" stroke-width="2"></circle>    
        <path fill="#AAAAAA" stroke="#000000" stroke-width="2" d="M10,10 L17,17"></path>
      </g>
    </svg>
  </div>
</div>

The svg element does not actually display. When I find the svg element in Chrome developer tools, both width and height show as zero.

I've tried removing the style attribute. I've tried setting the width and height in the style attribute.

I've copied the svg to a separate HTML file:

<html>
<head><title>maggen</title></head>
<body>
  <svg style="display: inline-block; verticalAlign: middle" width="18" height="18" xmlns="http://www.w3.org/2000/svg" version="1.1">
    <g>
      <circle cx="6" cy="6" r="5" fill="#AAAAAA" stroke="#000000" stroke-width="2"></circle>
      <path fill="#AAAAAA" stroke="#000000" stroke-width="2" d="M10,10 L17,17"></path>
    </g>
  </svg>
</body>
</html>

Where it displays fine.

If I wrap the svg element in a div, the svg element shows up. In fact, if I edit the HTML in Chrome developer tools it will show up.

So, yeah, why? I've done a search on Google for this, but either it isn't there or (more likely) my Google Fu is not up to the task. I mean, sure, I can wrap it in a div - and maybe that's the right thing to do - but I'd rather not because then I'd need to wrap other stuff in divs and the dom will start to get cluttered.

EDIT: On a hunch I tried editing viewport attribute into the SVG element in Chrome tools. Voila! The element is visible! Expect when I included the viewport attribute when creating the document, it's not visible. So I tried just adding a random attribute in Chrome tools to the SVG element. Voila! The Element is visible! So, I thought, the problem is specific to Chrome and tried running it in Firefox...

...where the element doesn't show up.

EDIT: Great, so wrapping it in a div is not guaranteed to make it show up. But doing an "edit as HTML" in Chrome developer tools does make it show up.

EDIT: Well, I've gotten it to work correctly and, yes, it turns out to be a function of the Javascript creating the DOM elements. There's a lot of stuff in the code, but I can boil it down to this:

This code works (createElement creates a tag and sets attributes based on passed in parameters):

var div = this.createElement(
  'div',
  element_name + '_div',
  null, style_options, null, null
);

div.innerHTML = [
  '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width=' + width + ' height=' + height + '>',
  svg_xml.join(''),
  '</svg>'
].join('');

if (parent) parent.appendChild(div);
return div;

This code doesn't:

var svg = this.createElement('svg', element_name, null, style_options, classlist, {
  viewport: '0 0 ' + width + ' ' + height,
  version: "1.1",
  xmlns: "http://www.w3.org/2000/svg",
  width: width,
  height: height
});

svg.innerHTML = svg_xml.join('');

if (parent) parent.appendChild(svg);
return svg;

So, sure, I've got something working now, but I don't understand why. Or more to the point, I don't understand why one way works and the other doesn't. I have a couple of guesses, but they are just wild guesses, really.

like image 258
aikimcr Avatar asked Jul 25 '14 17:07

aikimcr


People also ask

Why is SVG not showing up in Chrome?

Chrome browser will not display svg image, if it doesn't have with attribute with value in svg source code. Edit your SVG source code and add width attribute with desired value.

Why are my SVG images not showing?

If you are trying to use SVG like <img src="image. svg"> or as a CSS background-image , and the file is linked to correctly and everything seems right, but the browser isn't displaying it, it might be because your server is serving it with an incorrect content-type.

Can Chrome display SVG files?

From Chrome and Edge to Safari and Firefox, all the major browsers allow you to open SVG files these days — whether you're on a Mac or Windows. Just launch your browser and click on File > Open to choose the file you want to view. It'll then be displayed in your browser.


1 Answers

"I've got something working now, but I don't understand why."

The issue is that the methods you were using do not create an SVG element in the SVG namespace. The xmlns attribute only affects the behaviour of an XML parser, not of DOM methods.

I'm not sure which library you're using for the this.createElement() method with multiple parameters. However, I suspect it probably starts by calling the basic document.createElement(tagName) method. This is what MDN says about the standard DOM createElement method:

In an HTML document creates the specified HTML element or HTMLUnknownElement if the element is not known. ... In other documents creates an element with a null namespaceURI.

In other words, because you're (presumably, indirectly) calling createElement on an HTML document, it always creates an HTML element. An HTML element with tag name "svg" is just treated as an unknown span-type element.

In contrast, using div.innerHTML to pass a markup string creates the SVG element correctly because it invokes the HTML5 parser to figure out what type of element to create. The namespace is determined using the same rules as when parsing markup from a file. Editing the HTML in the Chrome developer tools has the same effect.

Sidenote: Avoid calling .innerHTML on an SVG element. Some browsers support it, but it's not part of the specs. You're not getting an error because your svg variable is actually an instance of HTMLUnknownElement. Passing SVG code to the innerHTML method of a parent <div> usually works, although there are some bugs with SMIL animation. As @Robert Longson says in the comments, you can use the DOMParser object to parse either HTML or XML code into a document.

The other way to dynamically create an SVG element is to use document.createElementNS(namespaceURI, tagName). You'll also have to use this method to create all the child elements of the SVG. Once they are created, you may be able to set attributes, styles, and classes using your library methods. (But you haven't specified what library you're using, so I'm not sure.)

like image 125
AmeliaBR Avatar answered Oct 12 '22 21:10

AmeliaBR