C
Qt Quick Ultralite map example
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
import QtQuick
import QtPositioning
import QtLocation
Item {
id: root
property real zoomLevel: mapParameters.zoomLevel
property real nextZoomLevel: root.zoomLevel + 1
property real prevZoomLevel: root.zoomLevel - 1
signal startDemoMode(bool paused)
signal endDemoMode
MapParameters {
id: mapParameters
}
function zoom(zoomType: string) {
if (zoomType === "In" && root.zoomLevel < map.maximumZoomLevel) {
zoomInAnimation.stop()
zoomInAnimation.start()
} else if (zoomType === "Out" && root.zoomLevel > map.minimumZoomLevel) {
zoomOutAnimation.stop()
zoomOutAnimation.start()
}
}
function incrementZoomLevel() {
if (root.zoomLevel < map.maximumZoomLevel)
root.zoomLevel += 1
}
function decrementZoomLevel() {
if (root.zoomLevel > map.minimumZoomLevel)
root.zoomLevel -= 1
}
function startDemo(paused: bool) {
if (paused) {
posSource.active = false
demoStartPause.imageSource = "start-resume.png"
demoStartPause.demoPaused = true
return
}
// start/resume
posSource.active = true
demoStartPause.imageSource = "pause.png"
demoStartPause.demoPaused = false
demoStop.visible = true
}
function endDemo() {
posSource.active = false
IndexManager.setIndex(0)
demoStartPause.imageSource = "start-resume.png"
demoStartPause.demoPaused = true
demoStop.visible = false
}
onStartDemoMode: startDemo(paused)
onEndDemoMode: endDemo()
PositionSource {
id: posSource
active: false
updateInterval: 1000
onPositionChanged: {
map.center.latitude = posSource.position.coordinate.latitude
map.center.longitude = posSource.position.coordinate.longitude
bearingAnimation.start()
}
onSourceErrorChanged: {
if (sourceError === PositionSource.ClosedError)
endDemo()
}
}
Map {
id: map
anchors.fill: parent
center {
latitude: mapParameters.latitude
longitude: mapParameters.longitude
}
bearing: mapParameters.bearing
zoomLevel: root.zoomLevel
minimumZoomLevel: mapParameters.minimumZoomLevel
maximumZoomLevel: mapParameters.maximumZoomLevel
MapMarker {
id: currentLocation
imageSource: "nav-arrow.png"
latitude: posSource.position.coordinate.latitude
longitude: posSource.position.coordinate.longitude
visible: !mapParameters.showButtons
}
MapMarker {
id: poiQt
imageSource: "location-marker.png"
markerText: "The Qt Company"
latitude: 65.05877
longitude: 25.45545
visible: !mapParameters.showButtons
}
MapMarker {
id: poiMarket
imageSource: "location-marker.png"
markerText: "Supermarket"
latitude: 65.054274
longitude: 25.456213
visible: !mapParameters.showButtons
}
MapMarker {
id: poiStation
imageSource: "location-marker.png"
markerText: "Gas Station"
latitude: 65.055253
longitude: 25.456561
visible: !mapParameters.showButtons
}
MouseArea {
id: mapPan
anchors.fill: parent
property real pressPointX: 0
property real pressPointY: 0
property real translationX: 0
property real translationY: 0
onPressed: {
pressPointX = mouse.x
pressPointY = mouse.y
translationX = 0
translationY = 0
}
onPositionChanged: {
var x = mouse.x - pressPointX
var y = mouse.y - pressPointY
var deltaX = x - translationX
var deltaY = y - translationY
translationX = x
translationY = y
map.pan(-deltaX, -deltaY)
}
}
MapButton {
id: zoomIn
visible: mapParameters.showButtons
width: root.width / 10
height: width
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: 10
anchors.rightMargin: 10
imageSource: "plus.png"
backgroundColor: "#e0e0e0"
onButtonClicked: {
if (zoomOutAnimation.running) {
zoomOutAnimation.stop()
}
zoom("In")
}
}
MapButton {
id: zoomOut
visible: mapParameters.showButtons
width: root.width / 10
height: width
anchors.top: zoomIn.bottom
anchors.right: parent.right
anchors.topMargin: 5
anchors.rightMargin: 10
imageSource: "minus.png"
backgroundColor: "#e0e0e0"
onButtonClicked: {
if (zoomInAnimation.running) {
zoomInAnimation.stop()
}
zoom("Out")
}
}
MapButton {
id: rotateRight
visible: mapParameters.showButtons
width: root.width / 10
height: width
anchors.top: zoomOut.bottom
anchors.right: parent.right
anchors.topMargin: 5
anchors.rightMargin: 10
imageSource: "rotate-right.png"
backgroundColor: "#e0e0e0"
onButtonClicked: {
map.bearing -= 5
}
}
MapButton {
id: rotateLeft
visible: mapParameters.showButtons
width: root.width / 10
height: width
anchors.top: zoomOut.bottom
anchors.right: rotateRight.left
anchors.topMargin: 5
anchors.rightMargin: 10
imageSource: "rotate-left.png"
backgroundColor: "#e0e0e0"
onButtonClicked: {
map.bearing += 5
}
}
MapButton {
id: demoStartPause
property bool demoPaused: true
width: root.width / 10
height: width
anchors.top: parent.top
anchors.right: zoomIn.left
anchors.topMargin: 10
anchors.rightMargin: 10
imageSource: "start-resume.png"
backgroundColor: "#e0e0e0"
onButtonClicked: {
startDemoMode(!demoPaused)
}
}
MapButton {
id: demoStop
visible: false
width: root.width / 10
height: width
anchors.top: parent.top
anchors.left: demoStartPause.right
anchors.topMargin: 10
anchors.leftMargin: 10
imageSource: "stop.png"
backgroundColor: "#e0e0e0"
onButtonClicked: {
endDemoMode()
}
onVisibleChanged: {
if (visible) {
// only on demo start not on resume
mapParameters.showButtons = false
root.zoomLevel = 17
map.minimumZoomLevel = 17
map.maximumZoomLevel = 17.9
demoZoomInTimer.start()
} else {
mapParameters.showButtons = true
root.zoomLevel = mapParameters.zoomLevel
map.minimumZoomLevel = mapParameters.minimumZoomLevel
map.maximumZoomLevel = mapParameters.maximumZoomLevel
map.bearing = mapParameters.bearing
}
}
}
CopyrightText {
id: copyrighttxt
anchors.bottom: parent.bottom
anchors.right: parent.right
copyrightText: "© OpenStreetMap contributors"
backgroundColor: "#e0e0e0"
}
}
PropertyAnimation {
id: zoomInAnimation
target: map
property: "zoomLevel"
from: root.zoomLevel
to: root.nextZoomLevel
running: false
alwaysRunToEnd: false
duration: 500
onStopped: incrementZoomLevel()
}
PropertyAnimation {
id: zoomOutAnimation
target: map
property: "zoomLevel"
from: root.zoomLevel
to: root.prevZoomLevel
running: false
alwaysRunToEnd: false
duration: 500
onStopped: decrementZoomLevel()
}
PropertyAnimation {
id: bearingAnimation
target: map
property: "bearing"
from: map.bearing
to: posSource.position.direction
running: true
duration: 2000
}
Timer {
id: demoZoomInTimer
interval: 2000
running: false
repeat: false
onTriggered: zoomInAnimation.start()
}
}