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 property string speedKmh: posSource.active && posSource.position.speedValid ? (posSource.position.speed * 3.6).toFixed(1) : "0.0" 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 coordAnimation.stop() 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.bearing = posSource.position.direction currentLocation.coordinate = posSource.position.coordinate } onSourceErrorChanged: { if (sourceError === PositionSource.ClosedError) endDemo() } } Map { id: map property bool panning: false anchors.fill: parent center: mapParameters.startPosition bearing: mapParameters.bearing zoomLevel: root.zoomLevel minimumZoomLevel: mapParameters.minimumZoomLevel maximumZoomLevel: mapParameters.maximumZoomLevel Behavior on bearing { RotationAnimation { duration: 600 direction: RotationAnimation.Shortest easing.type: Easing.InOutCubic } } MapMarker { id: currentLocation imageSource: "nav-arrow.png" coordinate: map.center visible: !mapParameters.showButtons Behavior on coordinate { CoordinateAnimation { id: coordAnimation duration: posSource.updateInterval } } onCoordinateChanged: { if (posSource.active && !map.panning) { map.center = currentLocation.coordinate } } } MapMarker { id: poiQt imageSource: "location-marker.png" markerText: "The Qt Company" coordinate: QtPositioning.coordinate(65.05877, 25.45545) visible: !mapParameters.showButtons } MapMarker { id: poiMarket imageSource: "location-marker.png" markerText: "Supermarket" coordinate: QtPositioning.coordinate(65.054274, 25.456213) visible: !mapParameters.showButtons } MapMarker { id: poiStation imageSource: "location-marker.png" markerText: "Gas Station" coordinate: QtPositioning.coordinate(65.055253, 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: { map.panning = true pressPointX = mouse.x pressPointY = mouse.y translationX = 0 translationY = 0 } onReleased: { map.panning = false } 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 } 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() } }