npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

leaflet-partially-editable-polyline

v0.2.0

Published

A Leaflet v2 plugin for editing only a local portion of a large polyline.

Readme

leaflet-partially-editable-polyline

A Leaflet v2 plugin for editing only a local portion of a large polyline.

Live Demo

PartiallyEditablePolyline extends Leaflet's Polyline and provides a lightweight editing interface that creates editor markers only around the currently selected point. This makes it possible to edit a small portion of a large polyline without creating markers for every point.

Status: Early development

This project is still under development. The public API may evolve as the implementation is reviewed and used.

Requirements

  • Leaflet v2 (tested with 2.0.0-alpha.1)
  • Modern browser with ES module support

This library currently targets Leaflet v2 and is not intended to support older Leaflet versions.

The source imports Leaflet with the bare module specifier "leaflet", so the application needs an import map or a bundler that resolves it. The application and the library must use the same Leaflet module instance; for example, a LatLng passed to startEditing() must be an instance of that module's LatLng class.

Features

  • Edit only a local portion of a large polyline
  • Existing points can be dragged to new positions
  • Midpoint markers can be dragged to insert new points
  • Existing points can be deleted using contextmenu
  • Only points within the current editing range receive editor markers
  • Editing markers are rebuilt when the editing target changes
  • External setLatLngs() calls are supported and rebuild the editing state
  • Editing operations are reported through dedicated events
  • The library does not manage application-specific metadata such as elevation or timestamps

Scope

This project is intentionally kept small and focused.

The library currently provides the editing interaction and geometry management required by the application that motivated it.

In particular, the following are outside the responsibility of this library:

  • Application-specific data structure or synchronization
  • Elevation calculation or interpolation
  • Timestamp management
  • Persistence
  • Undo/redo

The application using the library remains the source of truth for such data.

Installation

From npm

Install the library and Leaflet:

npm install leaflet-partially-editable-polyline leaflet

Then import the plugin and its stylesheet:

import { PartiallyEditablePolyline } from "leaflet-partially-editable-polyline";
import "leaflet-partially-editable-polyline/css";

The package has no build step and distributes its ESM source directly.

From the source files

Without npm, import the module directly from the source files:

import { PartiallyEditablePolyline } from "./src/leaflet-partially-editable-polyline.js";

Without a bundler

With no bundler and no npm install, the browser needs to resolve the bare specifier "leaflet" used by the source (see Requirements). An import map does this:

<script type="importmap">
  {
    "imports": {
      "leaflet": "https://unpkg.com/[email protected]/dist/leaflet.js"
    }
  }
</script>

This is how the demos under examples/ load both Leaflet and the library.

Usage

Once the library is available, here is how to use it.

Styling the editor markers

The editor markers are styled with plain CSS, using these class names:

.leaflet-partially-editable-polyline-point {
  width: 10px;
  height: 10px;
  background: #fff;
  border: 2px solid #3388ff;
  border-radius: 50%;
  box-sizing: border-box;
}

.leaflet-partially-editable-polyline-new-point {
  width: 8px;
  height: 8px;
  background: #3388ff;
  border: 2px solid #fff;
  border-radius: 50%;
  box-sizing: border-box;
  opacity: 0.5;
}

Add these rules (or your own version of them) to your application's stylesheet. These class names are part of the library's public API and only change with a breaking change.

The library also ships a default stylesheet (see Installation for importing it when installed from npm).

The stylesheet can also be linked or copied directly from the package if needed.

Without the stylesheet or equivalent application styles, editing still works, but the markers have no visible style.

Creating the polyline

Create a polyline in the same way as a normal Leaflet Polyline:

const editor = new PartiallyEditablePolyline(latlngs, {
  editablePointRadius: 100,
});

editor.addTo(map);

The polyline itself remains a Leaflet layer. The library does not start editing by itself; the application decides when editing starts. Editing can be started explicitly, once the polyline has been added to a map:

editor.startEditing(latlng);

or by responding to a polyline click (the library does not register a click handler on its own):

editor.on("click", (event) => {
  editor.startEditing(event.latlng);
});

When the user clicks elsewhere on the map, an application can end the current editing session:

map.on("click", () => {
  editor.endEditing();
});

API

new PartiallyEditablePolyline(latlngs, options)

Creates a polyline in the same way as a normal Leaflet Polyline.

latlngs is the initial geometry; see setLatLngs(latlngs) for the accepted formats and the normalization applied to it.

options is passed through to Polyline, together with the following options.

editablePointRadius

The library is designed for large polylines. When editing starts, the nearest point to the supplied LatLng is selected, and only a local range of points around that point receives editing markers. editablePointRadius is the number of points to include on either side of the selected point; with the default of 100, up to 201 points may get markers.

The range is recalculated after an insertion or a deletion, around the inserted point or, after a deletion, around the point that took the deleted point's position (the last point if the last one was deleted). Moving a point does not change the range. In all cases, the range only determines which points receive editor markers; the application continues to own the complete geometry.

The value must be a non-negative integer, or Infinity to include all points (0 shows a marker for the selected point only, with no midpoint markers). Any other value makes startEditing() throw a RangeError, without firing editingerror.

This option sets the default for every editing session, and can be overridden for a single session by passing the same option to startEditing() (see startEditing(latlng, options)).

Default: 100

Example:

const editor = new PartiallyEditablePolyline(latlngs, {
  editablePointRadius: 50,
});

pointIcon

Leaflet icon used for existing editable points.

newPointIcon

Leaflet icon used for midpoint markers.

The default icons are provided by the library.

startEditing(latlng, options)

Starts an editing session around the point nearest to the supplied Leaflet LatLng.

editor.startEditing(latlng);

The argument must be a Leaflet LatLng (an instance of the same Leaflet module's LatLng class). Anything else throws a TypeError; editingerror is not fired in this case.

The method does not accept a point index or a Leaflet event object. If the caller has a Leaflet event, pass its latlng property explicitly:

editor.startEditing(event.latlng);

The second argument is optional. It is an options object that can override the editable range for this editing session:

editor.startEditing(latlng, { editablePointRadius: 20 });

editablePointRadius replaces the value given to the constructor for this editing session only, including the ranges recalculated after an insertion or a deletion. The next session uses the constructor's value again unless it is overridden as well. An invalid value throws a RangeError; editingerror is not fired in this case.

If editing has been disabled with disableEditing(), startEditing() throws EditingDisabledError and fires the editingerror event.

If the polyline has not been added to a map, or has no points, the method does nothing and fires no event.

If an editing session is already active, it is ended first (editingend is fired) and then the new session starts (editingstart is fired).

EditingDisabledError is exported from the same module as PartiallyEditablePolyline.

endEditing()

Ends the current editing session.

If no editing session is active, this method does nothing and does not fire editingend.

editor.endEditing();

getEditablePointRange()

Returns the inclusive point-index range for the existing points that are currently editable:

const range = editor.getEditablePointRange();
// { startIndex, endIndex }, or null

The indices refer to the complete flat polyline. The method returns null when editing is not active or there are no editable existing points. A new object is returned on every call. The range may change after an insertion or deletion as the library rebuilds the local editing window.

enableEditing()

Enables editing.

editor.enableEditing();

disableEditing()

Disables editing.

If an editing session is active, it is ended immediately.

Subsequent calls to startEditing() throw EditingDisabledError.

editor.disableEditing();

setLatLngs(latlngs)

Replaces the whole geometry. This is the only supported way to change the geometry from outside the library: when the application's own data changes, pass the new coordinates to this method.

PartiallyEditablePolyline retains the Polyline#setLatLngs() method, but this library supports flat geometry only.

When called by the application:

  1. An active editing session is ended.
  2. The coordinates are copied and normalized to latitude and longitude (see Elevation and LatLng.alt), and the Polyline geometry is replaced with the copy.
  3. The library's internal editing state is rebuilt from the new geometry.

The same normalization is applied to the coordinates passed to the constructor.

Each element may be a LatLng, a [lat, lng] array, or a { lat, lng } object. Nested coordinate arrays are not supported and cause an error to be thrown.

addLatLng()

Not supported. addLatLng() always throws an error.

The polyline held by the library is an editing copy of the application's geometry (see Design), and changing the copy independently of the application's data is not supported. Update the application's own data and call setLatLngs() instead.

Events

The library emits the following editing events.

editingstart

Fired when an editing session starts.

Payload:

{
  index
}

index is the global index of the selected point in the complete flat polyline.

The editable markers have already been built when this event is fired, so getEditablePointRange() returns the new session's range in the handler.

editingend

Fired when an active editing session ends.

This happens when the session is ended by endEditing(), disableEditing() or setLatLngs(), when the layer is removed from the map, when startEditing() is called during an active session, or when the last remaining point is deleted.

No additional payload is provided.

pointchange

Fired once when an existing point has been moved and the drag operation has completed.

Payload:

{
  index,
  previousLatLng,
  latlng
}

index is the global index of the changed point.

The operation corresponds conceptually to:

latlngs[index] = latlng;

The event is fired after the library's internal geometry has been updated.

previousLatLng and latlng are independent LatLng snapshots and are not references to the library's internal objects.

pointinsert

Fired once when a midpoint marker has been dragged to insert a new point.

Payload:

{
  index,
  latlng
}

The operation corresponds conceptually to:

latlngs.splice(index, 0, latlng);

The event is fired after the insertion has been applied.

The editable range and markers have also been rebuilt, so getEditablePointRange() returns the post-insertion range in the handler.

The event represents the completed insertion. The midpoint drag does not generate an additional pointchange event.

pointdelete

Fired when an existing point is deleted.

Payload:

{
  index,
  latlng
}

index is the global index of the point immediately before deletion.

The operation corresponds conceptually to:

latlngs.splice(index, 1);

latlng is a snapshot of the deleted point.

The editable range and markers have already been rebuilt when this event is fired, so getEditablePointRange() returns the post-deletion range in the handler. When the last point is deleted it returns null, and editingend follows the pointdelete event.

There is no lower limit on the number of points. When the last remaining point is deleted, pointdelete is followed by editingend.

editingerror

Fired when an editing operation cannot be started.

For example, attempting to call startEditing() while editing is disabled produces:

{
  error
}

where error is an EditingDisabledError.

The error is also thrown by startEditing().

Event Ordering and Indices

Editing events describe completed operations and are emitted after the corresponding internal geometry/state update.

Indices are global indices in the complete flat polyline, not indices relative to the currently editable range.

Consumers should process events in emission order.

For example, after a pointinsert event, the geometry has already been updated before any subsequent event is interpreted.

This means that subsequent indices refer to the geometry state resulting from the preceding event, just as they would after a JavaScript array operation such as splice().

Elevation and LatLng.alt

The library does not manage elevation. The geometry held by the library is an editing copy that contains latitude and longitude only: alt values passed to the constructor or to setLatLngs() are discarded, and getLatLngs() and the latlng / previousLatLng values in events never contain alt.

Applications should keep elevation and other point data themselves and update it using the index in editing events.

Interaction

Existing point markers are draggable. While a marker is being dragged, the other editor markers are hidden and dashed helper lines to the adjacent points are shown; the polyline itself is updated when the drag ends.

Midpoint markers between editable points can be dragged to insert a new point.

Existing points can be deleted through Leaflet's contextmenu interaction, such as the standard desktop right-click interaction. The contextmenu interaction on a midpoint marker does nothing.

The library does not define application-level map interaction. For example, an application may use a polyline click to start editing and a map click to end editing.

Polyline and editor marker pointer events are configured so that their interaction does not unintentionally bubble into the map's general pointer handling.

Data Model

The library operates on a single flat sequence of Leaflet LatLng objects:

[
  LatLng,
  LatLng,
  LatLng,
  // ...
]

Each LatLng represents one point of the polyline and carries latitude and longitude only. The library treats this sequence as geometry and does not attach any application-specific meaning to individual points.

Applications that need to associate additional information with points or maintain application-specific data structures should manage that information separately and use the editing events to keep it in sync with the edited geometry.

Design

PartiallyEditablePolyline is implemented as a subclass of Leaflet's Polyline.

The polyline is an editing aid rather than the original data. It holds an editing copy of the geometry (latitude and longitude only), and the application remains the source of truth: editing results are reported through events, and the application applies them to its own data. When the application's data changes, it replaces the geometry with setLatLngs(); operations that would change the copy independently of the application's data, such as addLatLng(), are not supported.

The library deliberately keeps the editing state small:

  • The Leaflet geometry of the polyline is an editing copy of the complete geometry, not shared with the application's data.
  • The library keeps its own internal records of the points as its editing state.
  • Editor markers are created only for the current local editing range.
  • The application remains responsible for the semantic meaning and persistence of the data.

This separation allows the library to provide local editing without taking ownership of application-specific data structures.

Limitations

The current implementation has several intentional limitations:

  • Leaflet v2 only
  • Flat LatLng[] geometry only
  • LatLng.alt is discarded
  • addLatLng() is not supported
  • Directly modifying the array returned by getLatLngs(), or the LatLng objects in it, is not supported
  • No build step; the package distributes the source ESM directly
  • No compatibility layer for older Leaflet versions
  • Editing (moving, inserting, and deleting points) is mouse- and touch-only; there is no keyboard-only way to perform these operations

The project is still under development, so the public API may evolve.

Acknowledgements

This project was inspired by and developed with reference to Leaflet.js Editable Polylines plugin by tkrajina.

If you are using Leaflet v1, that plugin may be a suitable alternative. This project is specifically designed for Leaflet v2

License

This project is released under the Zero-Clause BSD License (0BSD).

See LICENSE for the full license text.