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 PolylineHandlesProviderPolylineHandlesProviderPolylineHandlesProvider and PolylineRingHandlesProviderPolylineRingHandlesProviderPolylineRingHandlesProvider, 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
IFeatureHandlesProviderIFeatureHandlesProviderIFeatureHandlesProvideruses 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
IFeatureHandlesProviderIFeatureHandlesProviderIFeatureHandlesProviderin anIFeatureEditConfigurationIFeatureEditConfigurationIFeatureEditConfigurationProgram: 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
IFeatureEditConfigurationIFeatureEditConfigurationIFeatureEditConfigurationon theFeatureLayerFeatureLayerFeatureLayer.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
FeatureFeatureFeature is provided by an IFeatureHandlesProviderIFeatureHandlesProviderIFeatureHandlesProvider. You can use the handle factory for the default implementation,
FeatureHandlesProviderFeatureHandlesProviderFeatureHandlesProvider 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.