2016-03-12 A Day Wasted

Gridmapper is a web application because it runs in a web browser. It consists of an SVG document and some Javascript which adds and removes elements to the SVG document in your browser’s memory. Sadly, where as SVG has a way to get key press events and mouse events and touch events – all the stuff Javascript knows about – it doesn’t have text fields and text areas like HTML does. So, what now? In theory, it’s easy: include XHTML in the SVG document – this is possible because both are XML dialects and SVG has an element that reserves space for non-SVG elements: foreignObject. So if I don’t want to re-implement all of the things that text fields and text areas do, all the cursor movements, selection, copy, cut, paste, and all that, then this is what I’ll have to do.

I currently have a way to do that, but I didn’t like it. It looks a bit off on the iPad Pro. It doesn’t look exactly the way I want it to on different operating systems. And so I decided to change it. Replace a lot of the XHTML other than the text area with pure SVG.

And then, when it was nearly done, I ran into weird problems with Chrome.

This was the first problem: When you click on the Download link, it turns invisible and some text that was invisible instead shows up. With the rewrite, making the Download link invisible turned all of the text invisible. Huh? After many iterations, I turned out that if I rearranged the links so that it wasn’t the first link, it worked. Huh?

The second problem was that the text area suddenly started jumping to the left if more than a few lines of code were inserted by the Text Export link. Huh?

I decided to kill it all. And now I’m sad.

Update: And literally minutes later, I think of something... try it... works!? The simple addition of “position: fixed” is the solution!? 🙀

Update: Oh well, I just found that the PNG export doesn’t work in Safari. Apparently not an unknown problem. [1] The solution in my case was to create a new SVG node and import all the nodes I need without importing any of the nodes containing the foreign objects:

  // PNG download hides user interface. We must actually *remove* all
  // the foreignObject elements because it causes a security exception
  // in Safari.
  // http://stackoverflow.com/questions/33972254/svgpng-from-canvas-todataurl-throws-dom-exception-18-security-error-in-safari-9
  var clone = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  var background = svg.getElementById('background');
  clone.setAttribute('width', svg.getAttribute('width'));
  clone.setAttribute('height', svg.getAttribute('width'));
  source = btoa(unescape(encodeURIComponent(new XMLSerializer().serializeToString(clone))));

  link  = document.getElementById('download_png');
  // SVG to PNG using canvas https://gist.github.com/gustavohenke/9073132
  var canvas = document.createElementNS(xhtmlNs, 'canvas');
  var rect = Map.ui.getBoundingClientRect();
  canvas.width = (Map.width + 2) * Map.tileWidth; // see resizeSVG
  canvas.height = (Map.width + 2) * Map.tileWidth;
  var ctx = canvas.getContext('2d');
  var img = document.createElementNS(xhtmlNs, 'img');
  img.setAttribute('src', 'data:image/svg+xml;base64,' + source);

  // when the image arrived in the canvas, set the link
  img.onload = function() {
    ctx.drawImage(img, 0, 0);
    link.setAttributeNS(xlinkNs, 'href', canvas.toDataURL('image/png'));

Update: I think I took care of all these issues and I even implemented a new feature: Z will now cycle through the following three states:

  1. hide other levels (the old functionality)
  2. use a black background
  3. back to the default: light gray background and transparent images of the levels above and below

Not wasted after all. :)



Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Please say HELLO.