This tutorial explains how you can customize an existing handles provider to:
-
Change the default settings of a handles provider
-
Customize the handles used by a handles provider
-
Make sure that the customized handles provider is used during editing
Other customizations
You need to customize a handles provider for advanced use cases only. For other customization methods, see this article. |
The code snippets in this tutorial are available in the editing sample.
See this article for more information about editing.
Configuring a handles provider
You can change the configuration of most handles provider implementations. For example, you can change the
minimum and maximum point counts for the PolylineHandlesProvider
PolylineHandlesProvider
PolylineHandlesProvider
and PolylineRingHandlesProvider
PolylineRingHandlesProvider
PolylineRingHandlesProvider
, or you can change the
handles they use.
The following sample code shows you how to create and customize a handles provider.
auto handlesProvider = std::make_shared<PolylineHandlesProvider>();
handlesProvider->setMaxPointCount(8);
var handlesProvider = new PolylineHandlesProvider {MaxPointCount = 8};
val handlesProvider = PolylineHandlesProvider()
handlesProvider.maxPointCount = 8
After creating a handles provider, you must configure it so that it’s used during editing:
-
Make sure that an
IFeatureHandlesProvider
IFeatureHandlesProvider
IFeatureHandlesProvider
uses the geometry handles provider.Program: Let the feature handles provider use the custom geometry handles provider// Register the custom handles provider in a default composite with a high priority, so that it is used before all other handles providers // Using a composite instead of directly using the custom PolylineHandlesProvider makes sure that other geometries remain supported. auto geometryHandlesProvider = CompositeGeometryHandlesProvider::createDefault(); geometryHandlesProvider->add(handlesProvider, Priority::high()); // Make sure the custom geometry handles provider is used to editing the features auto featureHandlesProvider = std::make_shared<FeatureHandlesProvider>(); featureHandlesProvider->setGeometryHandlesProvider(geometryHandlesProvider);
// Register the custom handles provider in a default composite with a high priority, so that it is used before all other handles providers // Using a composite instead of directly using the custom PolylineHandlesProvider makes sure that other geometries remain supported. var geometryHandlesProvider = CompositeGeometryHandlesProvider.CreateDefault(); geometryHandlesProvider.Add(handlesProvider, Priority.High); // Make sure the custom geometry handles provider is used to editing the features var featureHandlesProvider = new FeatureHandlesProvider {GeometryHandlesProvider = geometryHandlesProvider};
// Register the custom handles provider in a default composite with a high priority, so that it is used before all other handles providers // Using a composite instead of directly using the custom PolylineHandlesProvider makes sure that other geometries remain supported. val geometryHandlesProvider = CompositeGeometryHandlesProvider.createDefault() geometryHandlesProvider.add(handlesProvider, Priority.High) // Make sure the custom geometry handles provider is used to editing the features val featureHandlesProvider = FeatureHandlesProvider() featureHandlesProvider.geometryHandlesProvider = geometryHandlesProvider
-
Configure that
IFeatureHandlesProvider
IFeatureHandlesProvider
IFeatureHandlesProvider
in anIFeatureEditConfiguration
IFeatureEditConfiguration
IFeatureEditConfiguration
Program: Configure the feature handles provider in a feature edit configurationclass CustomEditConfiguration final : public IFeatureEditConfiguration { public: void edit(const Feature& /*feature*/, LayerId /*layerId*/, const std::shared_ptr<Map>& /*map*/, FeatureEditConfigurationBuilder& builder) const override { // Use a custom handles provider for all features builder.handlesProvider(_featureHandlesProvider).submit(); } private: std::shared_ptr<IFeatureHandlesProvider> _featureHandlesProvider; };
private sealed class CustomEditConfiguration : IFeatureEditConfiguration { private readonly IFeatureHandlesProvider _featureHandlesProvider; public void Edit(Feature feature, ulong layerId, Map map, FeatureEditConfigurationBuilder builder) { // Use a custom handles provider for all features builder.HandlesProvider(_featureHandlesProvider).Submit(); } }
private class CustomEditConfiguration : IFeatureEditConfiguration { private val featureHandlesProvider: IFeatureHandlesProvider override fun edit( feature: Feature, layerId: Long, map: Map, builder: FeatureEditConfigurationBuilder ) { // Use a custom handles provider for all features builder.handlesProvider(featureHandlesProvider).submit() } }
-
Configure that
IFeatureEditConfiguration
IFeatureEditConfiguration
IFeatureEditConfiguration
on theFeatureLayer
FeatureLayer
FeatureLayer
.Program: Configuring the feature edit configuration on the layer// Use a custom edit configuration that changes the editing behavior for this layer auto customEditConfiguration = std::make_shared<CustomEditConfiguration>(); // Register the configuration. This makes the layer editable by default return FeatureLayer::newBuilder() .model(model) // .title("Tutorial 1") .editConfiguration(customEditConfiguration) .build();
// Use a custom edit configuration that changes the editing behavior for this layer var customEditConfiguration = new CustomEditConfiguration(); // Register the configuration. This makes the layer editable by default return FeatureLayer.NewBuilder() .Model(model) .Title("Tutorial 1") .EditConfiguration(customEditConfiguration) .Build();
// Use a custom edit configuration that changes the editing behavior for this layer val customEditConfiguration = CustomEditConfiguration() // Register the configuration. This makes the layer editable by default return FeatureLayer.newBuilder() .model(model) // .title("Tutorial 1") .editConfiguration(customEditConfiguration) .build()
Changing the handles of a handle provider
For more fine-grained control over the handles used by a handles provider, you can implement your own handle factory. For example, if you implement your own handle factory for polylines, you can decide which handles it creates and uses to:
-
Move points
-
Remove points
-
Insert points
-
Change the elevation of a point
You can customize the handle factories for other geometries in a similar way. The handle to translate a
Feature
Feature
Feature
is provided by an IFeatureHandlesProvider
IFeatureHandlesProvider
IFeatureHandlesProvider
. You can use the handle factory for the default implementation,
FeatureHandlesProvider
FeatureHandlesProvider
FeatureHandlesProvider
to customize the translate handle.
The following sections show you how to implement and use a handle factory.
Using a handle factory wrapper
You can configure custom handle factory implementations, typically wrappers, on the corresponding handles provider.
// A custom handle factory provides fine-grained control over the handles that are used by the handles provider
auto defaultHandleFactory = handlesProvider->getHandleFactory();
auto customHandleFactory = std::make_shared<CustomPolylineHandleFactory>(defaultHandleFactory);
handlesProvider->setHandleFactory(customHandleFactory);
// A custom handle factory provides fine-grained control over the handles that are used by the handles provider
var defaultHandleFactory = handlesProvider.HandleFactory;
var customHandleFactory = new CustomPolylineHandleFactory(defaultHandleFactory);
handlesProvider.HandleFactory = customHandleFactory;
// A custom handle factory provides fine-grained control over the handles that are used by the handles provider
val defaultHandleFactory = handlesProvider.handleFactory
val customHandleFactory = CustomPolylineHandleFactory(defaultHandleFactory)
handlesProvider.handleFactory = customHandleFactory
Omitting a handle
To omit a type of handle, the corresponding factory method must return null.
std::shared_ptr<IEditHandle> CustomPolylineHandleFactory::createInsertPointHandle(const std::shared_ptr<Observable<std::shared_ptr<Polyline>>>& /*polyline*/,
size_t /*insertIndex*/,
const std::shared_ptr<IPointEditAction>& /*editAction*/,
const std::shared_ptr<FeatureEditContext>& /*context*/) {
// Make sure that PolylineHandlesProvider doesn't create insert handles anymore
// Note that it will still create append and prepend handles though.
return nullptr;
}
public override IEditHandle CreateInsertPointHandle(Observable<Polyline> polyline, uint insertIndex, IPointEditAction action, FeatureEditContext context)
{
// Make sure that PolylineHandlesProvider doesn't create insert handles anymore
// Note that it will still create append and prepend handles though.
return null;
}
override fun createInsertPointHandle(
polyline: Observable<Polyline?>,
insertIndex: Long,
editAction: IPointEditAction,
context: FeatureEditContext
): IEditHandle? {
// Make sure that PolylineHandlesProvider doesn't create insert handles anymore
return null
}
Replacing a handle
To replace a handle, you must re-implement the corresponding factory method. In the following example, we replace the handle to remove points from a polyline.
std::shared_ptr<IEditHandle> CustomPolylineHandleFactory::createRemovePointHandle(const std::shared_ptr<Observable<std::shared_ptr<Polyline>>>& polyline,
size_t pointIndex,
const std::shared_ptr<IPointEditAction>& editAction,
const std::shared_ptr<FeatureEditContext>& /*context*/) {
// Derive an observable Point from the observable Polyline. This point will be updated whenever the polyline is changed
auto observableLocation = ObservablePolylineUtil::derivePointAtIndex(polyline, pointIndex);
// Create a handle that is initially positioned on this location
auto handle = std::make_shared<PointEditHandle>(observableLocation);
// The handle will call the edit action when clicking on it using the right mouse button
handle->addOnClickAction(editAction, 1).mouseButton(MouseButton::right()).cursor(MouseCursor::arrow());
// The handle will call the edit action when performing a touch long press action
handle->addOnTouchLongPressAction(editAction).cursor(MouseCursor::arrow());
// Use a small red icon
handle->setRegularIcon(std::make_shared<BasicIcon>(IconType::FilledRectangle, 6, Color(255, 0, 0, 64)));
handle->setHighlightedIcon(std::make_shared<BasicIcon>(IconType::FilledRectangle, 6, Color(255, 0, 0, 192)));
return handle;
}
public override IEditHandle CreateRemovePointHandle(Observable<Polyline> polyline, uint pointIndex, IPointEditAction action, FeatureEditContext context)
{
// Derive an observable Point from the observable Polyline. This point will be updated whenever the polyline is changed
var observableLocation = ObservablePolylineUtil.DerivePointAtIndex(polyline, pointIndex);
// Create a handle that is initially positioned on this location
var handle = new PointEditHandle(observableLocation);
// The handle will call the edit action when clicking on it using the right mouse button
handle.AddOnClickAction(action, 1).MouseButton(MouseButton.Right).Cursor(MouseCursor.Arrow);
// The handle will call the edit action when performing a touch long press action
handle.AddOnTouchLongPressAction(action).Cursor(MouseCursor.Arrow);
// The handle will call the edit action when performing a touch long press action
handle.AddOnTouchLongPressAction(action).Cursor(MouseCursor.Arrow);
// Use a small red icon
handle.RegularIcon = new BasicIcon(BasicIcon.IconType.FilledRectangle, 6, Color.FromArgb(64, 255, 0, 0));
handle.HighlightedIcon = new BasicIcon(BasicIcon.IconType.FilledRectangle, 6, Color.FromArgb(192, 255, 0, 0));
return handle;
}
override fun createRemovePointHandle(
polyline: Observable<Polyline?>,
pointIndex: Long,
editAction: IPointEditAction,
context: FeatureEditContext
): IEditHandle {
// Derive an observable Point from the observable Polyline. This point will be updated whenever the polyline is changed
val observableLocation = ObservablePolylineUtil.derivePointAtIndex(polyline, pointIndex)
// Create a handle that is initially positioned on this location
val handle = PointEditHandle(observableLocation)
// The handle will call the edit action when performing a touch long press action
handle.addOnTouchLongPressAction(editAction).cursor(MouseCursor.Arrow)
// Use a small red icon
handle.regularIcon = BasicIcon(
BasicIcon.IconType.FilledRectangle,
6,
Color.valueOf(Color.argb(64, 255, 0, 0))
)
handle.highlightedIcon = BasicIcon(
BasicIcon.IconType.FilledRectangle, 6, Color.valueOf(
Color.argb(192, 255, 0, 0)
)
)
return handle
}
Adding a handle
You can’t use the handle factories to add an extra handle. It requires a different approach. For a demonstration, see this tutorial.