Parsing SVG with AngularJS - angularjs

I am new both to AngularJS and SVG so if i am doing something terribly wrong i apologize.
I am trying to create an SVG pattern with AngularJS:
Code fiddle:
http://jsfiddle.net/WFxF3/
Template:
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="grid" width="{{cubeWidth}}" height="{{cubeHeight}}" patternUnits="userSpaceOnUse">
<path d="M 0 0 L 0 {{cubeHeight}}" fill="none" stroke="gray" stroke-width="1" stroke-opacity="0.5"/>
<path d="M 0 0 L {{cubeWidth}} 0" fill="none" stroke="gray" stroke-width="1" stroke-opacity="0.5"/>
<!--<rect width="80" height="80" stroke="red" stroke-width="20" stroke-opacity="0.5" fill="white"/>-->
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)"/>
</svg>
Controller:
'use strict';
angular.module('gridifyApp')
.controller('MainCtrl', function ($scope) {
var docWidth = document.width;
var columns = 12;
var cubeWidth = docWidth / columns;
var cubeHeight = 44;
$scope.cubeWidth = cubeWidth;
$scope.cubeHeight = cubeHeight;
});
It seems to work and yet I get a console error:
Any ideas why?

The problem is svg is being parsed before angular is able to do anything so the value with double curly braces is invalid before angular gets to it. Angular's team has added a way to define some kind of "delayed binding". You can use it by prefixing desired attribute with ng-attr-. It waits untill the binding evaluation is valid and adds real attribute with proper value.
In your case it would be:
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="grid" ng-attr-width="{{cubeWidth}}" ng-attr-height="{{cubeHeight}}" patternUnits="userSpaceOnUse">
<path ng-attr-d="M 0 0 L 0 {{cubeHeight}}" fill="none" stroke="gray" stroke-width="1" stroke-opacity="0.5"/>
<path ng-attr-d="M 0 0 L {{cubeWidth}} 0" fill="none" stroke="gray" stroke-width="1" stroke-opacity="0.5"/>
<!--<rect width="80" height="80" stroke="red" stroke-width="20" stroke-opacity="0.5" fill="white"/>-->
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)"/>
</svg>
There should be no errors anymore. Remember to update your angular version.

SVG parsing happens before AngularJS can set any variable. You might try to create the SVG programmatically:
SVGSVGElement reference on MDN
Programmatically creating an SVG image element with JavaScript

Related

Glyphicon for ReactJs

I would like to use Glyphicon for my React Project. I followed this site https://www.golangprograms.com/reactjs-an-example-glyphicon-rating-star-component.html
for reference. It did not work. So I checked my react-bootstrap file in node_modules, there was no Glyphicon.
How can I import Glyphicon other than doing
<link rel="stylesheet" href="https://getbootstrap.com/docs/3.3/dist/css/bootstrap.min.css">
this.
Two options:
Reference the bootstrap icon page and copy the raw SVG element:
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-star-fill" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.283.95l-3.523 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
</svg>
Import and reference like so:
npm install bootstrap-icons
<svg class="bi" width="32" height="32" fill="currentColor">
<use xlink:href="bootstrap-icons.svg#star-fill"/>
</svg>

Any es6 method to un-escape an escaped html string?

I want to display the SVG using dangerouslySetInnerHTML.
<div dangerouslySetInnerHTML={{__html:props.SVG_Thumbnail__c}} />
However, the SVG data I got is an escaped HTML string.
I though this is a common case in Frontend. However, I did a google search none of built-in method could handle all the escaped chars perfectly.
The escape method doesn't work.
What's a common way to handle this string?
Write the replace methods every time?
var escaped = str.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>');
<svg width="100%" height="100%&q%" fill="#ffffff"/><text x="5%" y="50%" font-family="Lato" font-size="8px" alignment-baseline="middle" fill="#37444e">Primary Content</text></svg><svg x="10%" y="64%" width="90%" height="26%"><rect x="0" y="0" width="100%" height="100%" fill="#ffffff"/><text x="5%" y="50%" font-family="Lato" font-size="8px" alignment-baseline="middle" fill="#37444e">Secondary Content</text></svg></svg>
One thing you can do is assign the escaped value to an HTML element's innerHTML property, and then use the textContent property to get it back in unescaped form.
function unescapeHtml(value) {
var div = document.createElement('div');
div.innerHTML = value;
return div.textContent;
}
var escapedValue = '<svg width="100%" height="100%&q%" fill="#ffffff"/><text x="5%" y="50%" font-family="Lato" font-size="8px" alignment-baseline="middle" fill="#37444e">Primary Content</text></svg><svg x="10%" y="64%" width="90%" height="26%"><rect x="0" y="0" width="100%" height="100%" fill="#ffffff"/><text x="5%" y="50%" font-family="Lato" font-size="8px" alignment-baseline="middle" fill="#37444e">Secondary Content</text></svg></svg>';
var unescapedValue = unescapeHtml(escapedValue);
console.log(unescapedValue);

ng-include on SVG's but including dimensions

I like this technique, but as you all know, one of the great things about svg graphics is that you can re-size and re-use the same file. Is it possible to add a size variable to ng-include?
eg:
<div ng-include="'img/logo-rev.svg'" class="ng-scope" width="50">
The answer is to not specify a width or height in your SVG. Or if you do, make sure they are both set to "100%". Then as long as your SVG has a suitable viewBox attribute, it will scale to whatever size you make its parent.
.small {
width: 50px;
height: 50px;
}
.large {
width: 150px;
height: 150px;
}
<div class="small">
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="50" fill="green"/>
</svg>
</div>
<div class="large">
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="50" fill="green"/>
</svg>
</div>
Note that the two SVGs in the example above are identical.

Adding md-tooltip to a SVG chart?

This is an example:
<svg>
<g ng-repeat="rect in rectList">
<rect ng-attr-fill="rect.fill"
ng-attr-x="rect.x"
ng-attr-y="rect.y"
ng-attr-width="rect.width"
ng-attr-height="rect.height"></rect>
</g>
</svg>
I want to add a <md-tooltip> to each of these rects. Can I do it somehow? I am talking about the Angular Material Tooltip specifically, not any other tooltip implementation from other libraries.
Try to wrap it in a div and apply the md-tooltip
<div ng-repeat="status in statuses">
<md-tooltip md-direction="right">
{{status.description}}
</md-tooltip>
<svg >
<rect width="300" height="100" >
</rect>
</svg>
</div>
Here is the working Sample

add svg element at runtime in angular with 2 way data binding

I want to add svg element line at runtime with ng-attr-x1={{some scope varaible}}.
I tried 2 ways:
In 1 way I tried with $compile:
var g=angular.element(document.createElementNS("http://www.w3.org/2000/svg", "g"));
var line=$compile('<line ng-attr-x1={{$scope.array[array.length-1].x1}} ng-attr-y1={{$scope.array[array.length-1].y1}} ng-attr-x1={{$scope.array[array.length-1].x2}} ng-attr-x1={{$scope.array[array.length-1].y2}} style="with mandatory styling for line">')($scope);
g.append(line);
parentg.append(g);
In this method line is not showing and g is showing with 0px height and width.
In a 2 way I treid like :
var line=angular.element(document.createElementNS("http://www.w3.org/2000/svg", "line"));
line.attr('ng-attr-x1','scopeVariable');
line.attr('ng-attr-x2','scopeVariable');
line.attr('ng-attr-y1','scopeVariable');
line.attr('ng-attr-Y2','scopeVariable');
In this ng-attr attributes does not resolved to x and y. In DOM it shows as
This is possibly coming in way too late to help you, but I was stuck for a little while on the same question.
Turns out that $compile can take an element created with document.createElementNS() - like this:
var actApp = angular.module('actApp', []);
actApp.controller('shapeController', ['$scope', '$compile',
function shapeController($scope, $compile) {
$scope.color = 'green';
var svgEle = $(document.getElementById('mySvgElement'));
var line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', '0');
line.setAttribute('x2', '0');
line.setAttribute('x2', '20');
line.setAttribute('y2', '20');
line.setAttribute('style', 'stroke: {{color}};');
svgEle.append($compile(line)($scope));
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="actApp">
<div ng-controller="shapeController">
<input type="button" ng-click="color='blue'" value="To blue" />
<br />
<svg id="mySvgElement" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
</svg>
</div>
</div>
Hope this saves someone a little bit of time in the future.

Resources