Create and save a map as an ArcGIS PortalItem (i.e. web map).

Use case
Maps can be created programatically in code and then serialized and saved as an ArcGIS web map. A web map can be shared with others and opened in various applications and APIs throughout the platform, such as ArcGIS Pro, ArcGIS Online, the JavaScript API, Collector, and Explorer.
How to use the sample
- Select the basemap and layers you’d like to add to your map.
- Press the Save button.
- Sign into an ArcGIS Online account.
- Provide a title, tags, and description.
- Save the map.
How it works
- A
Mapis created with aBasemapand a few operational layers. - A
Portalobject is created and loaded. This will issue an authentication challenge, prompting the user to provide credentials. - Once the user is authenticated,
Map::saveAsis called and a newMapis saved with the specified title, tags, and folder.
Relevant API
- Map
- Map::saveAs
- Portal
Tags
ArcGIS Online, ArcGIS Pro, portal, publish, share, web map
Sample Code
// [WriteFile Name=CreateAndSaveMap, Category=Maps]// [Legal]// Copyright 2018 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
#ifdef PCH_BUILD#include "pch.hpp"#endif // PCH_BUILD
// sample headers#include "CreateAndSaveMap.h"
// ArcGIS Maps SDK headers#include "ArcGISMapImageLayer.h"#include "Basemap.h"#include "Error.h"#include "ErrorException.h"#include "Item.h"#include "LayerListModel.h"#include "Map.h"#include "MapQuickView.h"#include "MapTypes.h"#include "Portal.h"
// Qt headers#include <QFuture>#include <QUuid>
using namespace Esri::ArcGISRuntime;
CreateAndSaveMap::CreateAndSaveMap(QQuickItem* parent /* = nullptr */) : QQuickItem(parent){}
void CreateAndSaveMap::init(){ // Register the map view for QML qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView"); qmlRegisterType<CreateAndSaveMap>("Esri.Samples", 1, 0, "CreateAndSaveMapSample");}
void CreateAndSaveMap::componentComplete(){ QQuickItem::componentComplete();
// find QML MapView component m_mapView = findChild<MapQuickView*>("mapView");
// create the Portal object constexpr bool loginRequired = true; m_portal = new Portal(QUrl("https://www.arcgis.com"), loginRequired, this); connect(m_portal, &Portal::doneLoading, this, [this](const Error& e) { if (!e.isEmpty()) { return; }
emit portalLoaded(); });}
void CreateAndSaveMap::createMap(const QString& basemap, const QStringList& operationalLayers){ // Create the Basemap Basemap* selectedBasemap = nullptr; if (basemap == "Streets") { selectedBasemap = new Basemap(BasemapStyle::ArcGISStreets, this); } else if (basemap == "Imagery") { selectedBasemap = new Basemap(BasemapStyle::ArcGISImageryStandard, this); } else if (basemap == "Topographic") { selectedBasemap = new Basemap(BasemapStyle::ArcGISTopographic, this); } else if (basemap == "Oceans") { selectedBasemap = new Basemap(BasemapStyle::ArcGISOceans, this); }
// Create the Map with the basemap m_map = new Map(selectedBasemap, this);
// Add Operational Layers for (const QString& layer : operationalLayers) { if (layer == "WorldElevations") { ArcGISMapImageLayer* elevationLyr = new ArcGISMapImageLayer(QUrl("https://sampleserver5.arcgisonline.com/arcgis/rest/services/Elevation/WorldElevations/MapServer"), this); elevationLyr->setOpacity(0.5f); m_map->operationalLayers()->append(elevationLyr); } else if (layer == "Census") { m_map->operationalLayers()->append( new ArcGISMapImageLayer(QUrl("https://sampleserver5.arcgisonline.com/arcgis/rest/services/Census/MapServer"), this)); } }
// Set the Map on the MapView m_mapView->setMap(m_map);}
// Load the portal if not already loadedvoid CreateAndSaveMap::loadPortal(){ if (!m_portal) { return; }
if (m_portal->loadStatus() == LoadStatus::Loaded) { emit portalLoaded(); } else { m_portal->load(); }}
void CreateAndSaveMap::saveMap(const QString& title, const QString& tags, const QString& description){ if (!m_map || !m_portal) { return; }
// create save parameters const QStringList tagsList = tags.split(","); constexpr bool forceSave = false; const PortalFolder folder; const QByteArray thumbnail;
// save the map m_map->saveAsAsync(m_portal, title, tagsList, forceSave, folder, description, thumbnail) .then(this, [this]() { const QString itemId = m_map->item()->itemId(); emit saveMapCompleted(true, itemId); }) .onFailed([this](ErrorException e) { emit saveMapCompleted(false, "", QString("%1 %2").arg(e.error().message(), e.error().additionalMessage())); });}// [WriteFile Name=CreateAndSaveMap, Category=Maps]// [Legal]// Copyright 2018 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
#ifndef CREATEANDSAVEMAP_H#define CREATEANDSAVEMAP_H
// Qt headers#include <QQuickItem>
namespace Esri::ArcGISRuntime{ class Map; class MapQuickView; class Portal;} // namespace Esri::ArcGISRuntime
class CreateAndSaveMap : public QQuickItem{ Q_OBJECT
public: explicit CreateAndSaveMap(QQuickItem* parent = nullptr); ~CreateAndSaveMap() override = default;
void componentComplete() override; static void init(); Q_INVOKABLE void createMap(const QString& basemap, const QStringList& operationalLayers); Q_INVOKABLE void loadPortal(); Q_INVOKABLE void saveMap(const QString& title, const QString& tags, const QString& description);
signals: void portalLoaded(); void saveMapCompleted(bool success, const QString& itemId = "", const QString& error = "");
private: Esri::ArcGISRuntime::Map* m_map = nullptr; Esri::ArcGISRuntime::MapQuickView* m_mapView = nullptr; Esri::ArcGISRuntime::Portal* m_portal = nullptr;};
#endif // CREATEANDSAVEMAP_H// [WriteFile Name=CreateAndSaveMap, Category=Maps]// [Legal]// Copyright 2018 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
import QtQuickimport QtQuick.Controlsimport Esri.Samplesimport Esri.ArcGISRuntime.Toolkit
CreateAndSaveMapSample { id: rootRectangle clip: true width: 800 height: 600
onPortalLoaded: { stackView.push(options); }
onSaveMapCompleted: (success, itemId, error) => { if (stackView.currentItem === completionRect) return;
const url = "https://www.arcgis.com/home/item.html?id=%1".arg(itemId); stackView.push(completionRect, { text: success ? 'Map saved successfully.<br>View in <a href="%1">ArcGIS Online</a>'.arg(url) : "An error occurred while saving the map. Details: %1".arg(error) }); }
StackView { id: stackView anchors.fill: parent initialItem: layerWindow }
// add a mapView component MapView { id: mapView objectName: "mapView"
Component.onCompleted: { // Set the focus on MapView to initially enable keyboard navigation forceActiveFocus(); }
Pane { padding: 4 anchors { horizontalCenter: parent.horizontalCenter bottom: mapView.attributionTop margins: 5 } Button { anchors.centerIn: parent text: qsTr("Save map")
onClicked: { loadPortal(); } } }
}
Component { id: layerWindow LayerWindow { onCreateMapSelected: (basemap, layerList) => { stackView.push(mapView); createMap(basemap, layerList); } } }
// Window to display options for setting title, tags, and description Component { id: options SaveOptionsWindow { onCancelClicked: { stackView.pop(); }
onSaveMapClicked: (title, tags, description) => { saveMap(title, tags, description); } } }
// Rectangle to display completion text Component { id: completionRect Rectangle { property alias text: completeText.text
Text { id: completeText anchors.centerIn: parent
textFormat: Text.RichText horizontalAlignment: Text.AlignHCenter onLinkActivated: link => Qt.openUrlExternally(link) }
Button { anchors { horizontalCenter: parent.horizontalCenter bottom: parent.bottom margins: 5 } text: qsTr("Create New Map") onClicked: { // We need a local ref to the stackView and layerWindow // object as our object references will have been deleted // once "clear" cleans up this object. const sv = stackView; const lWindow = layerWindow; sv.clear(); sv.push(lWindow); } } } }
// Declare Authenticator to handle any authentication challenges Authenticator { anchors.fill: parent }}// Copyright 2018 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.
import QtQuickimport QtQuick.Layoutsimport QtQuick.Controls
Pane { signal createMapSelected(var basemap, var layerList)
background: Rectangle{ anchors.fill: parent color: palette.base }
Pane { padding: 10 anchors.centerIn: parent background: Rectangle { color: palette.mid border.color: palette.shadow border.width: 1 radius: 5 }
ColumnLayout { id: layerColumn anchors.centerIn: parent spacing: 8
Label { Layout.margins: 5 Layout.alignment: Qt.AlignHCenter text: qsTr("Select Layers") font { pixelSize: 18 family: "helvetica" } }
Label { Layout.margins: 5 text: qsTr("Select Basemap:") font { pixelSize: 14 family: "helvetica" } }
ComboBox { id: basemapComboBox property int modelWidth: 0 Layout.minimumWidth: modelWidth + leftPadding + rightPadding + (indicator ? indicator.width : 10) Layout.margins: 5 Layout.fillWidth: true model: [qsTr("Streets"), qsTr("Imagery"), qsTr("Topographic"), qsTr("Oceans")]
Component.onCompleted: { for (let i = 0; i < model.length; ++i) { metrics.text = model[i]; modelWidth = Math.max(modelWidth, metrics.width); } } TextMetrics { id: metrics font: basemapComboBox.font } }
Label { Layout.margins: 5 text: qsTr("Select Operational Layers:") font { pixelSize: 14 family: "helvetica" } }
Repeater { id: operationalLayerRepeater Layout.margins: 5 Layout.fillWidth: true model: [qsTr("WorldElevations"), qsTr("Census")]
CheckBox { text: modelData checked: true } }
Button { Layout.margins: 5 Layout.fillWidth: true text: qsTr("Create Map") onClicked: { const layerList = []; for (let i = 0; i < operationalLayerRepeater.count; i++) { const currentCheckbox = operationalLayerRepeater.itemAt(i); if (currentCheckbox.checked) { layerList.push(currentCheckbox.text) } } createMapSelected(basemapComboBox.currentText, layerList); } } } }}// Copyright 2018 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.
import QtQuickimport QtQuick.Controlsimport QtQuick.Layouts
Pane {
signal saveMapClicked(var title, var tags, var description) signal cancelClicked()
background: Rectangle{ anchors.fill: parent color: palette.base }
Pane { anchors.centerIn: parent background: Rectangle { color: palette.mid border.color: palette.shadow border.width: 1 radius: 5 }
GridLayout { id: layerColumn columns: 2 anchors { centerIn: parent margins: 16 }
Label { id: title Layout.columnSpan: 2 Layout.margins: 5 Layout.bottomMargin: 2 text: qsTr("Title*:") font { pixelSize: 14 family: "helvetica" } }
TextField { id: titleText selectByMouse: true Layout.columnSpan: 2 Layout.margins: 5 Layout.fillWidth: true Layout.topMargin: 0 placeholderText: qsTr("ex: Sample Map") }
Label { id: tags Layout.columnSpan: 2 Layout.margins: 5 Layout.bottomMargin: 2 text: qsTr("Tags:") font { pixelSize: 14 family: "helvetica" } }
TextField { id: tagsText selectByMouse: true Layout.columnSpan: 2 Layout.margins: 5 Layout.fillWidth: true Layout.topMargin: 0 placeholderText: qsTr("ex: map, sample, elevation") }
Label { id: description Layout.columnSpan: 2 Layout.margins: 5 Layout.bottomMargin: 2 text: qsTr("Description:") font { pixelSize: 14 family: "helvetica" } }
TextField { id: descriptionText selectByMouse: true Layout.columnSpan: 2 Layout.margins: 5 Layout.fillWidth: true Layout.topMargin: 0 placeholderText: qsTr("ex: This map displays...") }
Label { Layout.columnSpan: 2 Layout.margins: 5 text: qsTr("*Field is Required") color: "red" font { pixelSize: 10 family: "helvetica" } }
Button { Layout.margins: 5 text: qsTr("Save") onClicked: { // Make sure a Title is supplied if (titleText.text === "") { title.color = "red"; return; }
saveMapClicked(titleText.text, tagsText.text, descriptionText.text) } }
Button { Layout.margins: 5 text: qsTr("Cancel") onClicked: cancelClicked() } } }}// [WriteFile Name=CreateAndSaveMap, Category=Maps]// [Legal]// Copyright 2018 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
// ArcGIS Maps SDK headers#include "ArcGISRuntimeEnvironment.h"
// Qt headers#include <QCommandLineParser>#include <QDir>#include <QGuiApplication>#include <QQmlEngine>#include <QQuickView>
#ifdef QT_WEBVIEW_WEBENGINE_BACKEND#include <QtWebEngineQuick>#endif // QT_WEBVIEW_WEBENGINE_BACKEND
#include "Esri/ArcGISRuntime/Toolkit/register.h"
#ifdef Q_OS_WIN#include <Windows.h>#endif
#include "CreateAndSaveMap.h"
#define STRINGIZE(x) #x#define QUOTE(x) STRINGIZE(x)
int main(int argc, char* argv[]){#ifdef QT_WEBVIEW_WEBENGINE_BACKEND QtWebEngineQuick::initialize();#endif // QT_WEBVIEW_WEBENGINE_BACKEND
QGuiApplication app(argc, argv); app.setApplicationName(QString("CreateAndSaveMap"));
// Initialize the sample CreateAndSaveMap::init();
// Initialize application view QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView);
QString arcGISRuntimeImportPath = QUOTE(ARCGIS_RUNTIME_IMPORT_PATH);
#if defined(LINUX_PLATFORM_REPLACEMENT) // on some linux platforms the string 'linux' is replaced with 1 // fix the replacement paths which were created QString replaceString = QUOTE(LINUX_PLATFORM_REPLACEMENT); arcGISRuntimeImportPath = arcGISRuntimeImportPath.replace(replaceString, "linux", Qt::CaseSensitive);#endif
// Add the import Path view.engine()->addImportPath(QDir(QCoreApplication::applicationDirPath()).filePath("qml")); // Add the Runtime and Extras path view.engine()->addImportPath(arcGISRuntimeImportPath);
Esri::ArcGISRuntime::Toolkit::registerComponents(*(view.engine()));
// Set the source view.setSource(QUrl("qrc:/Samples/Maps/CreateAndSaveMap/CreateAndSaveMap.qml"));
view.show();
return app.exec();}