I have the following data structure:
'points': [
{
'x': 5535,
'y': 5535
},
{
'x': 5535,
'y': 60000
},
{
'x': 60000,
'y': 60000
},
{
'x': 60000,
'y': 5535
}
];
I would like to flatten it to 5535,5535 5535,60000 60000,60000 60000,5535
to use as a polyline
points
attribute.
I have the following in Polymer <template>
<polyline
id="polygon",
points="{{points | polygonPoints | toSvgPoints(width, height)}}"
stroke="rgba({{colour.r}}, {{colour.g}}, {{colour.b}}, {{opacity}})"
fill="rgba({{colour.r}}, {{colour.g}}, {{colour.b}}, {{opacity * 0.6}})"
stroke-width="{{lineWidth}}"
stroke-linecap="round"
stroke-linejoin="round"
/>
Where polygonPoints
and toSvgPoints
filters look like so:
/**
* Retrieves the polygon points for this object.
* @param point optionally provide a list of normalized points
* @returns the polygon points or all points if a line
*/
polygonPoints: function(points) {
var array = points.slice(0);
points = points || this.points;
array.push(points[0])
return array;
},
/**
* Retrieves the polygon points for this object.
* @param point optionally provide a list of normalized points
* @returns the polygon points or all points if a line
*/
toSvgPoints: function(points, width, height) {
var i, string = '';
points = points || this.points;
for (i = 0; i < points.length; ++i) {
string += this.normalizedToActual(points[i].x, width);
string += ',';
string += this.normalizedToActual(points[i].y, height);
string += ' ';
}
return string;
},
This works, the toSvgPoints
returns the correct points but the bindings to the point values do not get set up automagically by Polymer. For example, if I modify this.points[0].x = 4219
the polygon doesn't update because the binding hasn't been created to the polygon attribute.
Is this something that just can't be solved without providing some other method that invokes a redraw? Ideally I'd just want to do this:
<polyline
id="polygon",
points="{{x,y for (points | polygonPoints)}}"
...
/>
Which would stamp out the x
and y
values in the points
attribute and set up the bindings.
PolymerExpressions only observes objects that are directly referenced in an expression, so in this case it observes
points
, but not the properties on the elements in the array. If you replace a point, the expression will update, but it won't if you modify a point.There are a few ways to deal with this. If you know where a point is being modified, at you have a reference to the list there, you can manually notify on the list. I usually work with Polymer.Dart, but I think that the
notify()
function in observe-js is what you're looking for: https://github.com/Polymer/observe-js/blob/master/src/observe.js#L1076Alternatively, instead of returning a static projection of the points, have
toSvgPoints
listen to all of its dependencies:points
,x
andy
for each point,width
andheight
. When an input changes, update the output array. This will cause a chain of updates that propagates to your view.Use Polymer's observe-js library to do observation. It polyfills
Object.observe()
on platforms that don't have it. https://github.com/Polymer/observe-js#objectobserverI don't know for sure but I guess Polymer doesn't observe individual attributes inside an array. You could try to replace the item at that position:
this.points[0] = {x:4219,y:this.points[0].y}
or alternatively create a new array and set it to this.points ?
Well that took ages. Don't use a
polyline
use apath
:The
M {{points[0].x| max(width)}} {{points[0].y | max(height)}}
at the start of thed
attribute forces the redraw.