Display multiple MapPolygons via ListView and ListModel - qt

I would like to display multiple MapPolygons. To structre it nicely, I would like to define the polygons in a separated file.
After some googling around, I think an approach with ListView and ListModel could work.
So far I tried to define the complete MapPolygon inside the ListElement{}. This produced an error, that a ListElement{} can not contain any nested elements.
So I defiend a viarable path and color in the ListElement{} and tried to delegate those to a MapPolygon.
This produces the error: "ListElement: cannot use script for property value"
The ListView:
ListView {
model: PolygonCoords {}
delegate: MapPolygon {
color: color
path: path
}
}
The ListModel, PolygonCoords.qml:
ListModel{
ListElement{
color: "blue"
path: [ //very big
{latitude: 47.30985701233802, longitude: 8.957498557565305},
{latitude: 48.31223969058969, longitude: 12.959643094792634},
{latitude: 50.31281785500094, longitude: 12.960823612887165},
{latitude: 47.31281654102718, longitude: 8.962966471196324},
{latitude: 47.30862993050194, longitude: 8.963243902017013},
{latitude: 47.30863115391583, longitude: 8.963151349827395},
{latitude: 47.30697209667029, longitude: 8.962058898768426},
{latitude: 47.30985701233802, longitude: 8.957498557565305}
]
}
ListElement {
color: "red"
path: [ //very big
{latitude: 45.30985701233802, longitude: 7.957498557565305},
{latitude: 41.31223969058969, longitude: 11.959643094792634},
{latitude: 54.31281785500094, longitude: 11.960823612887165},
{latitude: 45.31281654102718, longitude: 7.962966471196324},
{latitude: 45.30862993050194, longitude: 7.963243902017013},
{latitude: 45.30863115391583, longitude: 7.963151349827395},
{latitude: 45.30697209667029, longitude: 7.962058898768426},
{latitude: 45.30985701233802, longitude: 7.957498557565305}
]
}
}
How do I have to change my path-Variable that it is not read as a script and
is the ListView even the right approach or is there a better option?
#Update Thanks to #folibis, I got it working with a Repeater as long the path and the repeater are in the same file as the map. Since the file with the map is already huge, I would like to move as much as possible in its own file.
I cannot begin a file with property var points, so I thought of using Item as a wrapper in PolygonCoords.qml:
Item {
property var points: [
{
color: Qt.rgba(0, 80, 128, 0.5),
path: [ //very big
{latitude: 47.30985701233802, longitude: 8.957498557565305},
{latitude: 48.31223969058969, longitude: 12.959643094792634},
{latitude: 50.31281785500094, longitude: 12.960823612887165},
{latitude: 47.31281654102718, longitude: 8.962966471196324},
{latitude: 47.30862993050194, longitude: 8.963243902017013},
{latitude: 47.30863115391583, longitude: 8.963151349827395},
{latitude: 47.30697209667029, longitude: 8.962058898768426},
{latitude: 47.30985701233802, longitude: 8.957498557565305}
]
},
{
color: Qt.rgba(128, 80, 0, 0.5),
path: [ //very big
{latitude: 45.30985701233802, longitude: 7.957498557565305},
{latitude: 41.31223969058969, longitude: 11.959643094792634},
{latitude: 54.31281785500094, longitude: 11.960823612887165},
{latitude: 45.31281654102718, longitude: 7.962966471196324},
{latitude: 45.30862993050194, longitude: 7.963243902017013},
{latitude: 45.30863115391583, longitude: 7.963151349827395},
{latitude: 45.30697209667029, longitude: 7.962058898768426},
{latitude: 45.30985701233802, longitude: 7.957498557565305}
]
}
]
}
And then calling it like this:
Repeater {
model: PolygonCoords.points
MapPolygon {
color: Polygoncoords.points[index].color
border {width: 2; color: "grey"}
path: PolygonCoords.points[index].path
}
}
Here I get no error, but the neither a MapPolygon on the map.
I also tried it with naming the Item with an id and calling it like this:
model: PolygonCoords.ItemID.points
But with this, I got the error: TypeError: Cannot read property points of undefined.
I further tried moving the repeater with the points together in another file and then just calling PolygonCoords. Again, no error and no MapPolygon:
Item {
Repeater {
model: PolygonCoords.points
MapPolygon {
color: Polygoncoords.points[index].color
border {width: 2; color: "grey"}
path: PolygonCoords.points[index].path
}
}
property var points: [
{
color: Qt.rgba(0, 80, 128, 0.5),
path: [ //very big
{latitude: 47.30985701233802, longitude: 8.957498557565305},
{latitude: 48.31223969058969, longitude: 12.959643094792634},
{latitude: 50.31281785500094, longitude: 12.960823612887165},
{latitude: 47.31281654102718, longitude: 8.962966471196324},
{latitude: 47.30862993050194, longitude: 8.963243902017013},
{latitude: 47.30863115391583, longitude: 8.963151349827395},
{latitude: 47.30697209667029, longitude: 8.962058898768426},
{latitude: 47.30985701233802, longitude: 8.957498557565305}
]
},
{
color: Qt.rgba(128, 80, 0, 0.5),
path: [ //very big
{latitude: 45.30985701233802, longitude: 7.957498557565305},
{latitude: 41.31223969058969, longitude: 11.959643094792634},
{latitude: 54.31281785500094, longitude: 11.960823612887165},
{latitude: 45.31281654102718, longitude: 7.962966471196324},
{latitude: 45.30862993050194, longitude: 7.963243902017013},
{latitude: 45.30863115391583, longitude: 7.963151349827395},
{latitude: 45.30697209667029, longitude: 7.962058898768426},
{latitude: 45.30985701233802, longitude: 7.957498557565305}
]
}
]
}
And in the file with the map:
PolygonCoords {}
To make sure, I referenced PolygonCords right, I defined just a MapPolygon in it. This one was properly displayed on the map.
Any idea what I am missing?

Here is example to illustrate idea I was talking about. I've used Repeater instead of ListView since it is more suitable for your purpose I guess. The data array could be stored in a different javascript file.
import QtQuick 2.11
import QtQuick.Controls 2.4
import QtLocation 5.6
import QtPositioning 5.6
ApplicationWindow {
id: mainWindow
width: 800
height: 600
visible: true
property var points: [
{
color: Qt.rgba(0, 80, 128, 0.5),
path: [
{latitude:59.91288302222718, longitude:10.728799819940349},
{latitude:59.91821810440818, longitude:10.737211227411649},
{latitude:59.912323649434825, longitude:10.754119873037723},
{latitude:59.90961270928307, longitude:10.764762878423767},
{latitude:59.90165073245826, longitude:10.759441375730745},
{latitude:59.908364741793115, longitude:10.748540878294307},
{latitude:59.9010050830971, longitude:10.741846084608},
{latitude:59.910387286199025, longitude:10.731632232668204},
]
},
{
color: Qt.rgba(128, 80, 0, 0.5),
path: [
{latitude:59.92101437751683, longitude:10.77077102661346},
{latitude:59.920842305970744, longitude:10.772916793815767},
{latitude:59.9168413910999, longitude:10.772830963132293},
{latitude:59.915206469874626, longitude:10.769741058354015},
{latitude:59.91787393143297, longitude:10.765792846683212},
]
}
]
Map {
id: map
anchors.fill: parent
plugin: Plugin { id: mapPlugin; name: "esri" }
center: QtPositioning.coordinate(59.91, 10.75)
zoomLevel: 14
MouseArea {
anchors.fill: parent
onPressed: {
var coord = map.toCoordinate(Qt.point(mouse.x,mouse.y));
console.log(coord.latitude, coord.longitude);
}
}
Repeater {
model: points
MapPolygon {
color: points[index].color
border{ width: 1; color: "grey" }
path: points[index].path
}
}
}
}

Related

QML Tableview change row color depending on row content

I'm new to qml and I need to write a simple list with 3 columns and an undefined number of rows showing the output of a log using a tableview. The first column shows the type (error, warning, info). Depending on this keywords I need to change the color of that row. I found code where I was able to change the color of all rows, but not individually depending on the data content. This is my starting point:
import QtQuick 2.13
import QtQuick.Window 2.11
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.4
import QtQuick.Controls 1.4 as QtC1
import QtQuick.Dialogs 1.2
ApplicationWindow {
id: applicationWindow
visible: true
width: 640
height: 480
title: qsTr("Log")
ListModel {
id: listModel
ListElement { category: 'warning'; type: "DEVICE IN USE"; comment: "Device with ID: PS-0002 is in use by Line with ID: L-0001A" }
ListElement { category: 'error'; type: "DEVICE IS OFFLINE"; comment: "Cannot reach device with ID: PS-0006 IP: 192.169.0.112 Port: 788" }
ListElement { category: 'info'; type: "DEVICE STATUS"; comment: "Device PS-00013 is ready for use." }
ListElement { category: 'info'; type: "DEVICE STATUS"; comment: "Device PS-00014 is ready for use." }
ListElement { category: 'info'; type: "DEVICE STATUS"; comment: "Device PS-00015 is ready for use." }
ListElement { category: 'info'; type: "DEVICE STATUS"; comment: "Device PS-00016 is ready for use." }
}
ColumnLayout
{
anchors.fill: parent
transformOrigin: Item.Center
Label {
id: logLabel
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
font.pixelSize: 22
text: qsTr("Summary")
Layout.topMargin: 13
}
QtC1.TableView {
id: tv
Layout.fillHeight: true
Layout.preferredHeight: 18
Layout.preferredWidth: 9
Layout.fillWidth: true
rowDelegate: Rectangle {
color: styleData.value ? "blue":"white"
}
/* Create columns */
QtC1.TableViewColumn
{
id: tv_category
horizontalAlignment: Text.AlignLeft
role: qsTr("category")
title: qsTr("Category")
width: 100
}
QtC1.TableViewColumn
{
id: tv_type
horizontalAlignment: Text.AlignLeft
role: qsTr("type")
title: qsTr("Type")
width: 100
}
QtC1.TableViewColumn
{
id: tv_comment
horizontalAlignment: Text.AlignRight
role: qsTr("comment")
title: qsTr("Comment")
width: contentWidth
}
model: listModel
}
}
}
Any help would be appreciated.
Martin
In the rowDelegate you have access to the row index (using styleData.row). Just use it to get the item from the list model like this:
rowDelegate: Rectangle {
color: {
var item = listModel.get(styleData.row)
if (item.category === "info")
return "skyblue"
else if (item.category === "warning")
return "yellow"
else if (item.category === "error")
return "red"
return "skyblue"
}
}

Ordering a feild (date) in simple Vega Data Table

I have a simple text vega ata table which we use in Kibana, it works fine, but I'm trying to find a way to order the results based on the arrival date, code below:
{
$schema: https://vega.github.io/schema/vega/v3.json
config: {
title: {offset: 20, fontSize: 14, font: "Helvetica", anchor:"start"}
}
title: {
text: Departure Airport Arrival Time
}
background: white
width: 1200
height: 100
padding: {"left": 0, "top": 5, "right": 5, "bottom": 5}
autosize: {type: "pad"}
// Define the data source
data: [
{
name: source
url: {
// change "index" to the name of the index
index: myindex*
"%context%": true
body: {
size: "10"
}
}
format: {property: "hits.hits"}
transform: [
{
type: flatten
// change fields to the actual path for flight segment but keep _source as a prefix
fields: ["_source.Something.FlightSegment"]
as: ["val"]
}
{
type: formula
as: x_position
expr: width * 1 / 4
}
{type: "formula", as: "line_height", expr: "20"}
{
type: stack
groupby: ["x_position"]
field: line_height
as: ["y0", "y1"]
}
]
}
]
marks: [
{
type: text
from: {data: "source"}
interactive: true
encode: {
enter: {
x: {field: "x_position", offset: -250}
y: {field: "y0"}
y2: {field: "y1"}
align: {value: "right"}
text: {field: "val.DepartureAirportCode"}
font: {value: "Helvetica"}
fontSize: {value: 14}
}
}
}
{
type: text
from: {data: "source"}
interactive: true
encode: {
enter: {
x: {field: "x_position", offset: -150}
y: {field: "y0"}
y2: {field: "y1"}
align: {value: "left"}
text: {field: "val.ArrivalDateTime"}
font: {value: "Helvetica"}
fontSize: {value: 14}
}
}
}
]
}
This is the result here:
You can see that the results are returned, but are out of order. What I would like to do is order it by ArrivalDateTime.
My problem is that most tutorials I have seen are for actual graphs and not for just plain old text.
Really appreciate anyone helping me out here.
I was curious about this too so found Vega lite sort
Especially sort by encoding from another field will do the job.

QML: Set Property of Nested ListElement

I have a ListModel like the following:
ListModel {
id: liveFeedModel
ListElement {
modelSrc: [
ListElement { src: "../img/pano.jpg" },
ListElement { src: "../img/pano1.jpg" },
ListElement { src: "../img/pano2.jpg" },
ListElement { src: "../img/pano3.jpg" }
]
name: "Cookies"
temp: "456 °C"
time: "--:--"
}
ListElement {
modelSrc: [
ListElement { src: "../img/pano2.jpg" }
]
name: "Sourdough Roll"
temp: "123 °F"
time: "--:--"
}
}
And I would like to set the value of the nested ListElements within modelSrc.
I am looking for something similar to:
liveFeedModel.get(0).modelSrc.get(2).src
except with set, setProperty, or something along those lines, instead of get
Thanks in advance
use:
myListView.model.get(0).modelSrc.setProperty(0, "src", "../img/pano2.jpg");
simple as that!

Arranging components in Sencha Touch 2

I need some help in Sencha Touch because I'm not familiar with it.
I want to arrange two buttons in the center of the page.
My problem is, that the container doesn't stretch in the place between the top- and bottom-toolbar.
Ext.define("AccessibleMap.view.ChooseView", {
extend: "Ext.form.Panel",
alias: "widget.chooseview",
initialize: function () {
console.log("Start");
this.callParent(arguments);
var topToolbar = {
xtype: "toolbar",
docked: "top",
title: "Accessible Map",
};
var locationButton = {
xtype: "button",
maxWidth: '60%',
minWidth: '50%',
text: "Standort ausgeben",
handler: this.onLocationBtnTap,
scope: this,
margin: '20 5 20 5'
};
var poisButton = {
xtype: "button",
maxWidth: '60%',
minWidth: '50%',
text: "POIs auswählen",
handler: this.onPoiBtnTap,
scope: this,
margin: '20 5 20 5'
};
var buttonCont ={
xtype: 'container',
style:{
background: 'red',
'margin-top':' 14%'
},
layout:{
type: 'vbox',
align: 'center'
},
items:[
locationButton,
poisButton
]
};
//buttons for bottom-toolbar
...
var tabpanel ={
xtype: 'toolbar',
docked: 'bottom',
layout:{
pack:'center',
type: 'hbox'
},
items: [ homeButton, locateButton, optionsButton, infoButton]
};
this.add([ topToolbar, buttonCont, tabpanel ]);
},
//listeners...
});
I colored the container red, thus I can see how big it is.
Making the container fullscreen results in an empty container.
Can somebody help me please?
I found an answer to this problem. I changed the code so that I don't have to call the initialize function. Instead, I put everything in the config settings.
Ext.define("AccessibleMap.view.ChooseView", {
extend: "Ext.form.Panel",
alias: "widget.chooseview",
config:{
layout:{
type: 'vbox',
pack: 'center'
},
items:[{
xtype: "toolbar",
docked: "top",
title: "Accessible Map",
},{
xtype: 'container',
flex: 1,
layout:{
type: 'vbox',
align: 'center'
},
items: [{
xtype: 'button',
...
}],
}],
listeners:[{ ...}]
}
});
As you can see, I defined the layout in the outer Panel to vbox with pack = center and the inner container to align = center. Moreover I defined a flex for the container.

Google Maps V3: Infowindows not resizing to fit information

Problem
I have a API V3 map, with a content window for each marker. The content of the infowindow stretches across multiple lines, but the infowindow does not resize to fit it all, causing an iframe-like scroll to appear.
I have looked at the setContent() method in the API which according to some posts on the API V3 mailing list should correct the issue. However, it looks like I've been putting into the wrong place thus causing the map not to load.
Infowindow content is populated from a field in the locations_array.
Map code
Here's the code I'm using, minus the setContent() method.
<script src="/_global/assets/scripts/jquery-1.2.6.min.js" type="text/javascript"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script language="javascript">
$(document).ready(function() {
//Google Maps
var myOptions = {
zoom: 5,
center: new google.maps.LatLng(-26.66, 122.25),
mapTypeControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControlOptions: { style: google.maps.MapTypeControlStyle.DROPDOWN_MENU },
navigationControl: true,
navigationControlOptions: { style: google.maps.NavigationControlStyle.SMALL }
}
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
// Create an array to hold a series of generic objects
// Each one will represent an individual marker, and contain all the
// information we need for that marker. This way, we can reuse the data
// on the client-side in other scripts as well.
var locations_array = [
{latitude: -35.015672, longitude: 117.879639, title: "Albany", infoWindowContent: "<strong>Albany</strong><br /><br />Get office details"},
{latitude: -33.351479, longitude: 115.666658, title: "Bunbury", infoWindowContent: "<strong>Bunbury</strong><br /><br />Get office details"},
{latitude: -24.850919, longitude: 113.731984, title: "Carnarvon", infoWindowContent: "<strong>Carnarvon</strong><br /><br />Get office details"},
{latitude: -33.361363, longitude: 116.161534, title: "Collie", infoWindowContent: "<strong>Collie</strong><br /><br />Get office details"},
{latitude: -33.847418, longitude: 121.884107, title: "Esperance", infoWindowContent: "<strong>Esperance</strong><br /><br />Get office details"},
{latitude: -31.795396, longitude: 115.88941, title: "Gnangara", infoWindowContent: "<strong>Gnangara</strong><br /><br />Get office details"},
{latitude: -33.082093, longitude: 115.913902, title: "Harvey", infoWindowContent: "<strong>Harvey</strong><br /><br />Get office details"},
{latitude: -33.082093, longitude: 115.913902, title: "Harvey Mill", infoWindowContent: "<strong>Harvey Mill</strong><br /><br />Get office details"},
{latitude: -30.749071, longitude: 121.472324, title: "Kalgoorlie", infoWindowContent: "<strong>Kalgoorlie</strong><br /><br />Get office details"},
{latitude: -33.691176, longitude: 117.557189, title: "Katanning", infoWindowContent: "<strong>Katanning</strong><br /><br />Get office details"},
{latitude: -32.531789, longitude: 115.721341, title: "Mandurah", infoWindowContent: "<strong>Mandurah</strong><br /><br />Get office details"},
{latitude: -34.250365, longitude: 116.147165, title: "Manjimup", infoWindowContent: "<strong>Manjimup</strong><br /><br />Get office details"},
{latitude: -33.982459, longitude: 115.765361, title: "Nannup", infoWindowContent: "<strong>Nannup</strong><br /><br />Get office details"},
{latitude: -31.953472, longitude: 115.914248, title: "Rivervale", infoWindowContent: "<strong>Rivervale</strong><br /><br />Get office details"},
{latitude: -31.948893, longitude: 115.795029, title: "Shenton Park", infoWindowContent: "<strong>Shenton Park</strong><br /><br />Get office details"},
{latitude: -34.214112, longitude: 116.074472, title: "West Manjimup", infoWindowContent: "<strong>West Manjimup</strong><br /><br />Get office details"},
];
// Now let's create some markers
for (var x = 0; x < locations_array.length; x++) {
// Grab an individual park object out of our array
var _park = locations_array[x];
var myLatlng = new google.maps.LatLng(locations_array[x].latitude,locations_array[x].longitude);
var marker = new google.maps.Marker({
map: map,
position: myLatlng,
title: locations_array[x].title,
icon: 'http://google-maps-icons.googlecode.com/files/park.png',
clickable: true,
infocontent: locations_array[x].infoWindowContent
});
google.maps.event.addListener(marker, 'click', function() {
var infowindow = new google.maps.InfoWindow({
content: this.infocontent
});
infowindow.open(map,this);
});
google.maps.event.addListener(marker, 'dblclick', function() {
map.setZoom(16);
});
}
});
</script>
Try putting the html strings of infoWindowContent in a div with a class that has a width set then change:
content: this.infocontent
to be
content: $(this.infocontent)[0]

Resources