I have this code where I need to display multiple small rectangles inside a big rectangle and I need to do this entire process multiple times.
here is my data:
"data": {
"rect1": {
"a":[10,20],
"b":[35,10]
},
"rect2": {
"y":[25,10],
"z":[55,20]
}
}
This data should make two rectangles rect1 and rect2 and two rectangles inside each of them a,b and y,z respectively. each small rectangle has start position x and width of that small rectangle for example a starts at x 10 and width=20.
<ul>
<li ng-repeat="(rect,coords) in data">
<svg>
<rect x=1 y=1 width=1000 height=50 style="fill:grey;" />
<span ng-repeat="coord in coords">
<rect x={{coord[0]}} y=1 width={{coord[1]}} height=50 style="fill:blue;" />
enter code here
But this code is not working as I have added ng-repeat line between the two tags.
image of what the final result should look like
I made this image in powerpoint so ignore the background.
You were pretty close. You can't use <span> inside an SVG. But most of the rest was correct.
Also it is better to use ng-attr-x="{{value}} instead of x="{{value}}. Otherwise the SVG parser will throw errors because it doesn't understand the string "{{value}}".
Here is a working example.
var app = angular.module('myApp', [])
app.controller("AppCtrl", ["$scope", function($scope) {
$scope.data = {
"rect1": {
"a":[10,20],
"b":[35,10]
},
"rect2": {
"y":[25,10],
"z":[55,20]
}
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<ul ng-controller="AppCtrl">
<li ng-repeat="(rectName, coords) in data">
<svg id="{{rectName}}" width="100%" height="50">
<rect x="1" y="1" width="1000" height="50"
style="fill: lightgrey;" />
<rect ng-repeat="(label, coord) in coords"
ng-attr-x="{{coord[0]}}" y="1"
ng-attr-width="{{coord[1]}}" height="50"
style="fill: blue;" />
<text ng-repeat="(label, coord) in coords"
ng-attr-x="{{coord[0]}}" y="25"
style="fill: white;">{{label}}</text>
</svg>
</li>
</ul>
</div>
Related
I've read a few other posts that are similar in nature on SO, but I still don't understand what I have done wrong.
I want to create multiple circles on a google map from a json string configured like:
[
{"name":"0","lat":30.45,"long":91.15},
{"name":"1","lat":0.0,"long":0.0},
{"name":"5","lat":0.0,"long":0.0}
]
I am hoping I can just iterate through the string and set the respective values.
The variable geofences is bound to the containing div with the ng-app declaration.
This is my current try:
<ng-map class=map zoom="15" center="[30.45, -91.15]">
<marker position="[30.45, -91.15]" />
<shape
ng-repeat="fence in geofences"
name="{{fence.name}}"
radius="40"
center="[{{fence.lat}}, {{fence.long}}]"
radius="40" />
<control name="overviewMap" opened="true" />
</ng-map>
I expect it has something to do with getting the values from a variable as if I hard code a value it works
This is what the Chrome developer console output:
angular.js:12332 TypeError: Cannot read property 'id' of undefined
and at the very bottom of the stack trace:
<shape ng-repeat="fence in geofences" name="{{fence.name}}" center="[{{fence.lat}}, {{fence.long}}]" radius="40" class="ng-scope >
What have I done incorrectly or worst case scenario how could I do something like this?
Most likely you are getting this error since google.maps.Circle object could not be created. shape directive expects name attribute that corresponds to map object (see below list), the provided values (e.g. "0" or "1") are invalid
The list of supported shape names:
circle
polygon
polyline
rectangle
groundOverlay
image
So, since your goal is to display circles, specify for name attribute cicrle value:
<shape ng-repeat="fence in geofences"
name="circle"
radius="40"
center="[{{fence.lat}}, {{fence.long}}]"
/>
Example
var app = angular.module('mapApp', ['ngMap']);
app.controller('mapCntrl', function ($scope) {
$scope.geofences = [
{ "name": "circle", "lat": 30.45, "long": -91.15 }
];
});
<script src="https://maps.google.com/maps/api/js?libraries=placeses,visualization,drawing,geometry,places"></script>
<script src="https://code.angularjs.org/1.3.15/angular.js"></script>
<script src="https://rawgit.com/allenhwkim/angularjs-google-maps/master/build/scripts/ng-map.js"></script>
<div ng-app="mapApp" ng-controller="mapCntrl">
<ng-map class=map zoom="15" center="[30.45, -91.15]">
<marker position="[30.45, -91.15]" />
<shape ng-repeat="fence in geofences"
name="circle"
radius="40"
center="[{{fence.lat}}, {{fence.long}}]"
/>
<control name="overviewMap" opened="true" />
</ng-map>
</div>
Plunker
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.
I'm looking for a (best-practice) way to iterate through a list of elements in the scope of an angular controller and generate a div with an element specific id and append a svg to the element specific div. I'm very new to Angular...and suspect that the following attempt fails because I misunderstand Angular bindings?
What is a better way to do the following:
<div id="top_level">
<div ng-repeat="item in items">
<div id={{item.id}}>
<script type="text/javascript">
var svg_img = build_svg(args);
document.getElementById({{item.id}}).appendChild(svg_img);
</script>
</div>
</div>
</div>
Thanks!
You should place your logic inside of your controller and conditionally render as much html as necessary rather than invoking a script tag inside of an ng-repeat..
<div ng-controller="YourCtrl">
<div id="top_level">
<div ng-repeat="item in items">
<div id={{item.id}}></div>
<div ng-bind-html="$scope.buildSvg(item)">
</div>
</div>
</div>
</div>
In your angular controller, you would then add a function to build out and return the svg for you to render.
app.controller('YourCtrl', ['$scope', function ($scope) {
$scope.buildSvg = function (item) {
// add logic here.
}
});
What does your function build_svg return?
We'd need a little more information about the kind of end-result you would like to get.
But yeah, it's not really good practice to have a script element within a ng-repeat directive.
I see two solutions here:
1- Build your SVG directly within the ng-repeat
<div id="top_level">
<div ng-repeat="item in items">
<div id={{item.id}}>
<svg height="{{item.svg.attrs.height}}" width="{{item.svg.attrs.width}}">
<circle cx="50" cy="50" r="40" stroke="black" stroke- width="3" fill="red" />
</svg>
</div>
</div>
</div>
Here is a plunker of this method:
http://plnkr.co/edit/g58BUPScjKHjRLAfx6ks?p=preview
2- Create a directive to generate your SVG with some additional parameters and flexibility.
<div id="top_level">
<div ng-repeat="item in items">
<div id={{item.id}}>
<my-svg attrs="item.svg.attrs"></my-svg>
</div>
</div>
</div>
The my-svg directive would generate a SVG element with the attrs parameters.
(N.B. This is a follow-on from another question.)
Here is some simple HTML, CSS, and AngularJS to display three pictures of bullfinches from flickr:
<html ng-app="AngularSVGTestApp">
<head>
<title>Angular SVG Image Size Test</title>
<style>
svg {
background-color: aqua;
}
</style>
</head>
<body ng-controller="MainCtrl as mainCtrl">
<div ng-cloak>
<svg ng-show="mainCtrl.svg.show" xmlns="http://www.w3.org/2000/svg" baseProfile="full" version="1.1" width="200" height="400">
<!-- https://www.flickr.com/photos/yeliseev/10116904936 -->
<image xlink:href="https://farm6.staticflickr.com/5535/10116904936_870f94488d_m.jpg"
x="20" y="20"
width="100" height="100"/>
<!-- https://www.flickr.com/photos/yeliseev/112992806 -->
<image xlink:href="https://farm1.staticflickr.com/38/112992806_780ebcd0ce_m.jpg"
x="20" y="140"
ng-attr-width="mainCtrl.svg.style.width"
ng-attr-height="mainCtrl.svg.style.height" />
<!-- https://www.flickr.com/photos/yeliseev/4433515854 -->
<image xlink:href="https://farm5.staticflickr.com/4058/4433515854_41152445a9_m.jpg"
x="20" y="260"
ng-style="mainCtrl.svg.style" />
</svg>
</div>
<script src="/Scripts/angular.js"></script>
<script>
angular.module('AngularSVGTestApp', [])
.controller('MainCtrl', [function () {
var self = this;
self.svg = {
show: true,
style: {
width: 100,
height: 100
}
};
}]);
</script>
</body>
</html>
fiddle
The three bullfinch images within the SVG differ in how their size is set.
Has its width and height set to 100 explicitly in the HTML
Has its width and height set to 100 using ng-attr-width and ng-attr-height to bind to model values held in the controller
Has its width and height set to 100 using ng-style to bind to model values held in the controller
Why don't either of these latter two methods work? What should I use to bind the dimensions of an image in an SVG from AngularJS?
it should be like, here is the doc
ng-attr-width="{{mainCtrl.svg.style.width}}"
ng-attr-height="{{mainCtrl.svg.style.height}}"
jsFiddle
as for ngStyle
here is the answer . In short, I don't think you can do that with ngStyle.
Here is some ref. It shows you how to do it in CSS correctly.
I'm trying to launch an ng-click function inside an ng-repeat but I get a problem, while clicking the element, the function always pick the last occurrence of my loop.
To be more precise here's an example:
<div ng-controller="qualityController">
<div ng-repeat="quality in qualities">
<img src ={{ asset('bundles/mybundle/img/jauge_normal.png') }} width="160" height="160" alt="Circle" usemap="#circle">
<div class="g-performance-rate-knob">
<input type="text" data-angleOffset=180 data-angleArc=360 data-fgColor="#ff7200" data-width="116" data-height="116" data-step="0.1" data-min="0" data-max="100" data-readOnly=true knob class="dial" ng-model="quality.note">
</div>
<map name="circle" id="circle" ng-click="loadQualityDetail(quality.id)">
<area shape="circle" coords="80,80,80" data-toggle="modal" data-target="#modal-stars-{[{ quality.id }]}" class="more" alt=""/>
</map>
</div>
</div>
Js:
app.controller('qualityController', function ($scope,$http)
{
qualities = [];
qualities.push({id : 1});
qualities.push({id : 2});
qualities.push({id : 3});
qualities.push({id : 4});
$scope.loadQualityDetail = function(qualityId)
{
console.log(qualityId);
}
});
Wherever I click, I get "4" in my console.
Note: I use jQuery Knob library. But it seems like the problem appear on map or area elements.
If you need more information please tell me I could make a fiddle.
Thanks by advance,