SVG with selectors from query not working
-
Hello, im trying to make an interactive SVG
I have many data points that i get with a query and then im trying to assign them dynamically with a loop to an svg ..
Basically if the value of the data point is 0 i want to style my fill with red, If the value is less than the average of all the datapoints then i want the fill to be orange and if the value is more than the average leave the color as is ...
Seems that my div ma-selector is not correct
Any idea on how to do this ?
Once my ma-selector is correct should i make a function to switch the ng-class ? what you think is the best way to do it since i have more than 300 data points in that ng-repeatThank you
<ma-point-query query="'or(name=like=STR_*)'" limit="300" points="points1"></ma-point-query> <ma-point-values points="points1" values="combined" from="dateBar.from" to="dateBar.to" rollup="AVERAGE" rollup-interval="1 DAYS"> </ma-point-values> <ma-svg ng-include="'/rest/v2/file-stores/public/100 Pixel_Linne Vert.svg'"> <div ng-repeat="value in combined"> <div ng-repeat="point in points1"> <div ma-selector="#point.name" ng-style="{'fill': (value['value_' + point.xid]) == 0 ? 'red' : 'green'}"></div> </div> </div> </ma-svg>
thats my svg .. for example the STR_508 has a value of 0 but the ng-style is not assgined to the selector
-
I like what you're doing, looks nifty.
"{'fill': (value['value_' + point.xid]) == 0 ?
should be"{'fill': (value['value_' + point.xid].value) == 0 ?
That will help compare your values. Although note for making future modifications simpler, if you apply a class instead you have more control over the look/behaviour without having to dig into your html template layout to make changes. Means you can add effects such as flashing/fading or bold borders or whatever else it is you want to alert the user to.EDIT:
The combined array will likely be in the format of combined[point.xid].values=[value array w/ timestamp], simply output combined into your dashboard (make sure you only output a few points of data!) with{{combined}}
to see the format of the output and confirm it.
You may have to use an index in your ng-repeat fromng-repeat="value in combined"
tong-repeat="(index,value) in combined"
then apply your style like this:"{'fill': (combined['value_' + point.xid][index].value) == 0 ?
Good luck!
-
@alexzer You can't use a
ng-repeat
inside<ma-svg>
like that unfortunately. What<ma-svg>
does is just look in its children for anything with ama-selector
attribute, it then uses that selector to find elements inside the SVG, it then applies the extra attributes (e.g.ng-style
) to the elements it finds inside the SVG. After this is done, AngularJS compiles the markup inside the SVG.I think to achieve what you are trying to do it might be easiest to add the AngularJS markup inside the SVG. e.g. you can add
<rect ng-repeat="point in points1" ng-style="..."></rect>
inside your SVG. -
@Jared-Wiltshire thank you !
I spent so many hours debugging why the ng-repeat was not working ..
Ok so how exactly i add <rect ng-repeat="point in points1" ng-style="..."></rect> inside my SVG ?
Its my first time with Inkscape .. in the xml editor ? i have no clue ! -
@alexzer I would do it in a text editor but yes I believe that Inkscape will let you add arbitrary attributes and edit the XML inside the application.
-
OH shoot I completely missed that! Thanks Jared! Hope I was correct regarding the value property at least!
@alexzer I believe what Jared is saying involves copying the <rect> element information so rather than having
<div ng-repeat="point in points1"> <div ma-selector="#point.name" ng-style="{'fill': (value['value_' + point.xid]) == 0 ? 'red' : 'green'}"></div> </div>
So it would become (Must be in svg file!)
<rect ng-repeat="point in points1" ng-style="{'fill': (value['value_' + point.xid]) == 0 ? 'red' : 'green'}" />
or to that effect
-
@mattfox said in SVG with selectors from query not working:
So it would become
It would have to go inside the SVG file, not inside the
<ma-svg>
element so no need for ama-selector
attribute. -
@Jared-Wiltshire thanks, for that. Have never used SVG elements, always used images and css sprites. I've learnt a few things today. Have amended the code above and removed the selector attribute.
-
hi :) thanks for both of your responses..
It seems very simple but unfortunately is not working ..
I added the code to my svg and i realize through various debug that the ng-style="{'fill': (value['value_' + point.xid]) == 0 ? 'red' : 'green'}" inside the <rect tag of the svg is not working .. the value of the xid never gets a value ..
To sum up i put the code so you can see also the output .
this is few line of the svg edited in a text editor ( i dont put all of it because i have hundreds of rect)<svg <rect ng-repeat="point in points1" ng-style="{'fill': (value['value_' + point.xid]) == 0 ? 'red' : 'green'}" /> <rect id="STR_920" width="11.97" height="0.97" x="9" y="2" ry="0.25" style="fill:#674ea7;fill-opacity:1;stroke-width:7" /> <rect id="STR_508" width="11.97" height="0.97" x="45" y="44.4" ry="0.25" style="fill:#999999;fill-opacity:1;stroke-width:7" />
My html in mango is
<ma-get-point-value point-xid="ST_000508" point="ST_000508"></ma-get-point-value> <ma-get-point-value point-xid="ST_000509" point="ST_000509"></ma-get-point-value> <ma-get-point-value point-xid="ST_000510" point="ST_000510"></ma-get-point-value> <ma-point-query query="'or(name=like=STR_5*)'" limit="24" points="points1"></ma-point-query> <ma-point-values points="points1" values="combined" from="dateBar.from" to="dateBar.to" rollup="AVERAGE" rollup-interval="1 DAYS"> </ma-point-values> COMBINED: <br> {{combined}} <br> <div ng-repeat="(index,value) in combined"> <div ng-repeat="point in points1">XID: {{point.xid}} , Time: {{value.timestamp | maMoment:'format':'DD/MM/YYYY'}} ,Point Name: {{point.name}} ,Point Value: {{value['value_' + point.xid]}}</div> </div> <ma-svg ng-include="'/rest/v2/file-stores/public/LosetoMap_Modified.svg'"> </ma-svg>
My output is :
and above the output of the svg i have these for debug (i put it in code but its not code its the output of the html {{combined}} and the 2 div ng-repeatCOMBINED: [{"timestamp":1529359200000,"value_ST_000501":2.5324797453703702,"value_ST_000502":2.4958472222222223,"value_ST_000503":2.45721875,"value_ST_000504":2.527818287037037,"value_ST_000505":2.5340474537037037,"value_ST_000506":2.446441550925926,"value_ST_000507":2.4828055555555557,"value_ST_000509":2.606719328703704,"value_ST_000510":2.495085648148148,"value_ST_000511":2.483042824074074,"value_ST_000512":2.474778935185185,"value_ST_000513":2.4917071759259257,"value_ST_000514":2.477402199074074,"value_ST_000515":2.503596064814815,"value_ST_000516":2.4979340277777777,"value_ST_000517":2.6329930555555556,"value_ST_000518":2.530654513888889,"value_ST_000519":2.508365162037037,"value_ST_000520":2.4927065972222224,"value_ST_000521":2.5036099537037035,"value_ST_000522":2.5136047453703703,"value_ST_000523":2.543189236111111,"value_ST_000524":0,"value_ST_000508":0},{"timestamp":1529445600000,"value_ST_000501":2.362199446875,"value_ST_000502":2.323173372337963,"value_ST_000503":2.288589725,"value_ST_000504":2.358256738541667,"value_ST_000505":2.366965667013889,"value_ST_000506":2.263396686226852,"value_ST_000507":2.3154054489583333,"value_ST_000509":2.4408835403935183,"value_ST_000510":2.3216632368055556,"value_ST_000511":2.3201079952546295,"value_ST_000512":2.298350141666667,"value_ST_000513":2.318909483449074,"value_ST_000514":2.3095914775462965,"value_ST_000515":2.341121900578704,"value_ST_000516":2.3271681804398145,"value_ST_000517":2.466752191087963,"value_ST_000518":2.359174562615741,"value_ST_000519":2.359262277314815,"value_ST_000520":2.3289390302083333,"value_ST_000521":2.3426141127314817,"value_ST_000522":2.341633474652778,"value_ST_000523":2.3748450319444445,"value_ST_000524":0,"value_ST_000508":0}] XID: ST_000501 , Time: 19/06/2018 ,Point Name: STR_5.01 ,Point Value: 2.5324797453703702 XID: ST_000502 , Time: 19/06/2018 ,Point Name: STR_5.02 ,Point Value: 2.4958472222222223 XID: ST_000503 , Time: 19/06/2018 ,Point Name: STR_5.03 ,Point Value: 2.45721875 XID: ST_000504 , Time: 19/06/2018 ,Point Name: STR_5.04 ,Point Value: 2.527818287037037 XID: ST_000505 , Time: 19/06/2018 ,Point Name: STR_5.05 ,Point Value: 2.5340474537037037 XID: ST_000506 , Time: 19/06/2018 ,Point Name: STR_5.06 ,Point Value: 2.446441550925926 XID: ST_000507 , Time: 19/06/2018 ,Point Name: STR_5.07 ,Point Value: 2.4828055555555557 XID: ST_000509 , Time: 19/06/2018 ,Point Name: STR_5.09 ,Point Value: 2.606719328703704 XID: ST_000510 , Time: 19/06/2018 ,Point Name: STR_5.10 ,Point Value: 2.495085648148148 XID: ST_000511 , Time: 19/06/2018 ,Point Name: STR_5.11 ,Point Value: 2.483042824074074 XID: ST_000512 , Time: 19/06/2018 ,Point Name: STR_5.12 ,Point Value: 2.474778935185185 XID: ST_000513 , Time: 19/06/2018 ,Point Name: STR_5.13 ,Point Value: 2.4917071759259257 XID: ST_000514 , Time: 19/06/2018 ,Point Name: STR_5.14 ,Point Value: 2.477402199074074 XID: ST_000515 , Time: 19/06/2018 ,Point Name: STR_5.15 ,Point Value: 2.503596064814815 XID: ST_000516 , Time: 19/06/2018 ,Point Name: STR_5.16 ,Point Value: 2.4979340277777777 XID: ST_000517 , Time: 19/06/2018 ,Point Name: STR_5.17 ,Point Value: 2.6329930555555556 XID: ST_000518 , Time: 19/06/2018 ,Point Name: STR_5.18 ,Point Value: 2.530654513888889 XID: ST_000519 , Time: 19/06/2018 ,Point Name: STR_5.19 ,Point Value: 2.508365162037037 XID: ST_000520 , Time: 19/06/2018 ,Point Name: STR_5.20 ,Point Value: 2.4927065972222224 XID: ST_000521 , Time: 19/06/2018 ,Point Name: STR_5.21 ,Point Value: 2.5036099537037035 XID: ST_000522 , Time: 19/06/2018 ,Point Name: STR_5.22 ,Point Value: 2.5136047453703703 XID: ST_000523 , Time: 19/06/2018 ,Point Name: STR_5.23 ,Point Value: 2.543189236111111 XID: ST_000524 , Time: 19/06/2018 ,Point Name: STR_5.24 ,Point Value: 0 XID: ST_000508 , Time: 19/06/2018 ,Point Name: STR_508 ,Point Value: 0
Basically the ng-style="{'fill': (value['value_' + point.xid]) == 0 ? 'red' : 'green'}" is not working inside the svg .. We need the id also right ? because in the ma-selector the id of the rect was the point.name .. so i thought i had to add it also in the svg
I wonder if the loop is enough in the svg, so i tried few other things in the svg but none worked :<rect ng-repeat="point in points1" id="{{point.name}}" ng-style="{'fill': ST_000508.value == 0 ? 'red' : 'green'}" /> <rect ng-repeat="point in points1" ng-repeat="value in combined" id="{{point.name}}" ng-style="{'fill': ST_000508.value == 0 ? 'red' : 'green'}" /> <rect ng-repeat="point in points1" ng-repeat="value in combined" id="{{point.name}}" ng-style="{'fill': (value['value_' + point.xid]) == 0 ? 'red' : 'green'}" /> <rect ng-repeat="point in points1" id="{{point.name}}" ng-style="{'fill': (value['value_' + point.xid]) == 0 ? 'red' : 'green'}" /> <rect ng-repeat="value in combined" ng-repeat="point in points1" id="{{value['value_' + point.xid]}}" ng-style="{'fill': (value['value_' + point.xid]) == 0 ? 'red' : 'green'}" /> <rect ng-repeat="(index,value) in combined" ng-repeat="point in points1" id="{{point.name}}" ng-style="{'fill': (combined['value_' + point.xid][index].value) == 0 ? 'red' : 'green'}" />
As you see i even tried to pass directly the point.xid.value as from a specific data point ST_000508.value .. in the html this is working .. but not in the svg
The rect tag in the svg is wrong right ? need one or two loops including the value in combined ? do i need the id in the rect of the svg ?
Im sorry to ask you so many things but there is no much documentation around the ma-svg and it seems so simple but might be not !
Thank you very much -
@alexzer said in SVG with selectors from query not working:
{'fill': (value['value_' + point.xid]) == 0 ? 'red' : 'green'}
please try
{fill: (value['value_' + point.xid]) == 0 ? 'red' : 'green'}
just from looking at other examples on the web. they do not appear to wrap the css style in quotes... But on second thought that likely won't change anything.
Note that only one ng-repeat is required per element. Also good job with outputting the combined values. we can see that the value should be:value_ST_000501
so keep your format tovalue['value_' + point.xid]
Also looking at your svg, don't know if it's beacuse you've copied snippets but is your svg format
<sgv> <!-- svg closed with '>' --> <rect/> <rect/> <rect/> </svg>
My final suggestion is this:
in the rect element output:ng-attr-fill="value['value_' + point.xid]) == 0 ? 'red' : 'green'"
Rather than trying to use style.
-
i tried it .. quotes is not the problem
as you saw in my example of the svg code i try to print the value even in the id to debug it but its not working
In my svg i have<rect ng-repeat="point in points1" id="{{value['value_' + point.xid]}}" ng-style="{fill: (value['value_' + point.xid]) == 0 ? 'red' : 'green'}" />
and then in rendered html through chrome inspect i see 24 div's ( the limit of my query) and all of those rendered div are the same:
<rect ng-repeat="point in points1" id="" ng-style="{fill: (value['value_' + point.xid]) == 0 ? 'red' : 'green'}" style="fill: green;"></rect>
So obviously even the id has no value so thats why its doesnt get value also in the ng-style ...
the id="{{value['value_' + point.xid]}}" is null .. so its the wrong way to get the value right ?And how the svg is goint to retreive the value from the combined just by one ng-repeat="point in points1" and without the loop of the actual value in combined ng-repeat="value in combined" ??
In my html i have those loops nested as<div ng-repeat="(index,value) in combined"> <div ng-repeat="point in points1">XID: {{point.xid}} , Time: {{value.timestamp | maMoment:'format':'DD/MM/YYYY'}} ,Point Name: {{point.name}} ,Point Value: {{value['value_' + point.xid]}}</div> </div>
but in my svg you suggest me to keep only one ng-repeat ? not the value in combined ?
so the above code with the 2 nested loops in my html that works good and we can see the output is equivalent to the following wth only one loop ?<rect ng-repeat="point in points1" ng-style="{'fill': ST_000508.value == 0 ? 'red' : 'green'}" />
im confused !!
-
<div ng-repeat="(index,value) in combined"> <rect ng-repeat="point in points1" id="" ng-style="{fill: (value['value_' + point.xid]) == 0 ? 'red' : 'green'}" style="fill: green;"></rect> </div>
-
@MattFox You can't put a
<div>
inside a SVG like that,<div>
is HTML not SVG.@alexzer Yes you will need nested loops if you want to dynamically generate your rows and your columns from the point values and the points.
You probably want an outer
ng-repeat
on a<g>
element (group) and then an innerng-repeat
of the actual<rect>
elements. If you do it this way you will obviously need to dynamically adjust the position/offset of the elements based on the$index
of theng-repeat
. You are going to have some knowledge of SVG markup in order for this to work.People typically do not use SVG like this, they draw a fixed layout in a program like Illustrator or Inkscape then bind a each individual element to a piece of data from the AngularJS scope. Since it seems that you have drawn a fixed grid maybe you should do this instead i.e. do not use a
ng-repeat
.So, for example you might have one row like this
<rect ng-style="{fill: combined[0]['value_xid_one'] ? 'red' : 'green'}" ...></rect> <rect ng-style="{fill: combined[0]['value_xid_two'] ? 'red' : 'green'}" ...></rect>
And the next would be
<rect ng-style="{fill: combined[1]['value_xid_one'] ? 'red' : 'green'}" ...></rect> <rect ng-style="{fill: combined[1]['value_xid_two'] ? 'red' : 'green'}" ...></rect>
-
@jared-wiltshire Cool thanks. I'll leave this to you.
-
@alexzer Here's an example of both approaches. Change the url in the page to try the two different approaches:
Page (dashboard markup):
<ma-watch-list-get ng-model="designer.watchList" parameters="designer.parameters" on-points-change="designer.points = $points" id="33366719-20b2-4f57-8d86-61145fc36354" watch-list-xid="WL_f942f3de-bafb-4318-93ee-1932762031a8"></ma-watch-list-get> <div class="ma-designer-root" id="8a47a1c9-b651-497e-8a7c-64b350497174" style="width: 1366px; height: 768px; position: relative;"> <ma-svg id="9f7c2bd8-5268-4ff0-a1a2-d29bdfbe8e21" ng-include="'/rest/v2/file-stores/public/drawing-ng-repeat.svg'" style="position: absolute; left: 0px; top: 0px;"></ma-svg> <ma-point-values id="f10206bd-bfd9-43ad-8d7c-72b2ac7cf540" points="designer.points" from="dateBar.from" to="dateBar.to" rollup="{{dateBar.rollupType}}" rollup-interval="{{dateBar.rollupIntervals + ' ' + dateBar.rollupIntervalPeriod}}" style="position: absolute; left: 0px; top: 600px;" values="combined"></ma-point-values> </div>
drawing.svg
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 600" height="600" width="800"> <g transform="translate(0,0)"> <rect y="0" x="0" height="50" width="100" style="fill:none;stroke:#000000;stroke-width:2;" ng-style="{fill: combined[0]['value_binary'] ? 'red' : 'green'}" /> <text y="30" x="10"><tspan>Row 1, col 1</tspan></text> </g> <g transform="translate(100,0)"> <rect y="0" x="0" height="50" width="100" style="fill:none;stroke:#000000;stroke-width:2;" ng-style="{fill: combined[0]['value_voltage'] > 10 ? 'red' : 'green'}" /> <text y="30" x="10"><tspan>Row 1, col 2</tspan></text> </g> <g transform="translate(0,50)"> <rect y="0" x="0" height="50" width="100" style="fill:none;stroke:#000000;stroke-width:2;" ng-style="{fill: combined[1]['value_binary'] ? 'red' : 'green'}" /> <text y="30" x="10"><tspan>Row 2, col 1</tspan></text> </g> <g transform="translate(100,50)"> <rect y="0" x="0" height="50" width="100" style="fill:none;stroke:#000000;stroke-width:2;" ng-style="{fill: combined[1]['value_voltage'] > 10 ? 'red' : 'green'}" /> <text y="30" x="10"><tspan>Row 2, col 2</tspan></text> </g> </svg>
drawing-ng-repeat.svg
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 600" height="600" width="800"> <g ng-repeat="value in combined | limitTo: 10" ng-attr-transform="translate(0,{{$index * 50}})"> <g ng-repeat="pt in designer.points" ng-attr-transform="translate({{$index * 100}},0)"> <rect y="0" x="0" height="50" width="100" style="fill:none;stroke:#000000;stroke-width:2;" ng-style="{fill: value['value_' + pt.xid] ? 'red' : 'green'}" /> <text y="30" x="10"><tspan>{{pt.xid}} @ {{value.timestamp | maMoment:'format':'l LTS'}}</tspan></text> </g> </g> </svg>