When setting a renderer on a feature layer, a PictureMarkerSymbol rotates with the map rotation.
There is an angle field on a PictureMarkerSymbol. If you set this then the icon/graphic will be displayed rotated on the map. I tried binding the angle property to the map.mapRotation property but the icon didn't rotate with the map.
Is there any way to alter the rotation of the graphic dynamically with the map? My intent is actually to keep the graphic unrotated on the screen regardless of the map rotation underneath it.
UniqueValueRenderer{
attributeNames: ["Verified"]
defaultSymbol: PictureMarkerSymbol { image: "image.png"; width: 40; height: 32; angle: (map.mapRotation * -1.00)}
}
Solved! Go to Solution.
I don't know what all of the code looks like for this, but it seems like it is "by design" for 10.2.x release of Runtime. The issue is probably that Symbols are value objects, so the binding will not work. Once you set a symbol on a Renderer or a Unique Value Info, it is set. If you then change the original symbol, or if the binding emits that the property updates, it will indeed update the symbol, but that symbol is a copy of the one that is actually applied to the renderer or unique value info.
So with that said, the workflow you need to do is every single time the map's rotation changes, update each symbol's rotation to be the same as the map's, then re-set all of the symbols to the renderer. Quite a lot of work for something so simple, but I believe this is how it will have to be done.
Our Quartz release will have symbols as references, so if you update the symbol (or use property binding in the case of QML), it will update the symbol, and the renderer will automatically update, as it holds a reference to the original symbol.
Hope this helps.
-Luke
Please see the Rendering Mode Sample in AppStudio.
You can set the rendering mode for a Graphics Layer to be Static or Dynamic:
GraphicsLayer {
id: graphicsLayerDynamic
renderingMode: Enums.RenderingModeDynamic
}
This will preserve or rotate the graphics with the map;
Hope this helps,
Hannah
Hi Paul,
If you want to continue to user a feature layer, I found that just using mapRotation will tend to keep the icon upright. I must admit it doesn't seem perfectly react to the mapRotation.
FeatureLayer {
id: featureLayer
featureTable: featureServiceTable
renderer: SimpleRenderer {
symbol: PictureMarkerSymbol {
image: "./Alfred_E._Neuman.png"
width: 32
height: 32
angle: (map.mapRotation)
}
}
}
Hi Gareth
Had another look at this one yesterday. It seems the rotation binding works for the default symbol, but not for the ones that get added. Below is the code I used, and it appears that when the 'notVerifiedUvi' is added it uses the current map rotation but this then doesn't remain as a binding so isn't updated dynamically.
Any idea of an alternate method of creating this renderer that would retain the dynamic binding for all UniqueValueInfo objects?
UniqueValueRenderer{
attributeNames: ["Verified"]
defaultLabel: "Verification unknown"
defaultSymbol: PictureMarkerSymbol { image: "images/FMP_GREY_SupplyFlag.png"; width: 40; height: 32; angle: (map.mapRotation)}
Component.onCompleted: { addValue(notVerifiedUvi); }
}
UniqueValueInfo{
id: notVerifiedUvi;
value: ["N"]
label: "Not Verified"
symbol: PictureMarkerSymbol { image: "images/FMP_RED_SupplyFlag.png"; width: 40; height: 32; angle: (map.mapRotation) }
}
Hi Paul,
A nice curly one for the morning! Straight out I think it is going to be a bug/by design.
A couple of things I quickly thought of.
map.onMapRotationChanged.connect(function(){ text = map.mapRotation})
http://doc.qt.io/qt-5/qtqml-syntax-signals.html
I tried this on a Text component at both the text property and the Compoonent.onCompleted and the rotation updated. Let me know how you go. P.S. Lucas Danzinger any other thoughts?
I don't know what all of the code looks like for this, but it seems like it is "by design" for 10.2.x release of Runtime. The issue is probably that Symbols are value objects, so the binding will not work. Once you set a symbol on a Renderer or a Unique Value Info, it is set. If you then change the original symbol, or if the binding emits that the property updates, it will indeed update the symbol, but that symbol is a copy of the one that is actually applied to the renderer or unique value info.
So with that said, the workflow you need to do is every single time the map's rotation changes, update each symbol's rotation to be the same as the map's, then re-set all of the symbols to the renderer. Quite a lot of work for something so simple, but I believe this is how it will have to be done.
Our Quartz release will have symbols as references, so if you update the symbol (or use property binding in the case of QML), it will update the symbol, and the renderer will automatically update, as it holds a reference to the original symbol.
Hope this helps.
-Luke
Hi Gareth and Luke
Thanks for your input - taking your comments, I have got it working by doing the following...
Defining PictureMarkerSymbol objects outside of the UniqueValueInfo object.
Then adding a function to the renderer that removes all UVIs, reapplies the symbols to the UVIs and re-adds them to the renderer, then reapplies the renderer itself back to the layer.
Then, last step was to add a handler that catches the map rotating, updates the rotation angle of each of the PictureMarkerSymbols before calling the refresh function on the renderer.
A bit longwinded but gets there in the end! A small delay as it updates typically several hundred labels on the screen but not too bad.
onMapRotationChanged: {
//console.log("the map rotation changed to: ", map.mapRotation)
redFlagPictureMarkerSymbol.angle = map.mapRotation;
greenFlagPictureMarkerSymbol.angle = map.mapRotation;
greyFlagPictureMarkerSymbol.angle = map.mapRotation;
myRenderer.refresh();
}
UniqueValueRenderer{
id:myRenderer
defaultSymbol: greyFlagPictureMarkerSymbol;
Component.onCompleted: { addValue(uvi1); addValue(uvi2) }
function refresh(){
removeAll();
uvi1.symbol = redFlagPictureMarkerSymbol
uvi2.symbol = greenFlagPictureMarkerSymbol
addValue(uvi1);
addValue(uvi2);
myLayer.renderer = myRenderer;
}
}