From 24d257770b0d73feb050623030539a484bf2664d Mon Sep 17 00:00:00 2001 From: Peter Bastyi Date: Tue, 29 Sep 2020 16:17:48 +0200 Subject: [PATCH 1/6] Initial lasso mode --- debug/app.js | 6 ++ debug/index.html | 3 +- dist/mapbox-gl-draw.css | 3 + docs/API.md | 10 ++- src/constants.js | 3 + src/events.js | 2 + src/feature_types/lasso.js | 71 ++++++++++++++++++ src/modes/draw_lasso.js | 144 +++++++++++++++++++++++++++++++++++++ src/modes/index.js | 2 + src/options.js | 2 + src/ui.js | 10 +++ 11 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 src/feature_types/lasso.js create mode 100644 src/modes/draw_lasso.js diff --git a/debug/app.js b/debug/app.js index c83df4a0c..a4c5da4d0 100644 --- a/debug/app.js +++ b/debug/app.js @@ -99,6 +99,12 @@ map.on('load', () => { Draw.changeMode('draw_polygon'); }; + // Jump into draw polygon mode via a custom UI element + const startLasso = document.getElementById('start-lasso'); + startLasso.onclick = function() { + Draw.changeMode('draw_lasso'); + }; + // Jump into static mode via a custom UI element const startStatic = document.getElementById('start-static'); startStatic.onclick = function() { diff --git a/debug/index.html b/debug/index.html index d62eaf1b7..a36706cb2 100644 --- a/debug/index.html +++ b/debug/index.html @@ -12,7 +12,7 @@ body { margin:0; padding:0; } html, body, #map { height: 100%; } .start-draw { - width: 315px; + width: 385px; position: absolute; left :10px; bottom: 10px; @@ -37,6 +37,7 @@
+
LASSO
STATIC
POINT
LINE
diff --git a/dist/mapbox-gl-draw.css b/dist/mapbox-gl-draw.css index d1da29cb4..8cf2e869c 100644 --- a/dist/mapbox-gl-draw.css +++ b/dist/mapbox-gl-draw.css @@ -39,6 +39,9 @@ .mapbox-gl-draw_polygon { background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjIwIiAgIGhlaWdodD0iMjAiICAgdmlld0JveD0iMCAwIDIwIDIwIiAgIGlkPSJzdmcxOTE2NyIgICB2ZXJzaW9uPSIxLjEiICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MStkZXZlbCtvc3htZW51IHIxMjkxMSIgICBzb2RpcG9kaTpkb2NuYW1lPSJzcXVhcmUuc3ZnIj4gIDxkZWZzICAgICBpZD0iZGVmczE5MTY5IiAvPiAgPHNvZGlwb2RpOm5hbWVkdmlldyAgICAgaWQ9ImJhc2UiICAgICBwYWdlY29sb3I9IiNmZmZmZmYiICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIgICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIiAgICAgaW5rc2NhcGU6em9vbT0iMTEuMzEzNzA4IiAgICAgaW5rc2NhcGU6Y3g9IjExLjY4MTYzNCIgICAgIGlua3NjYXBlOmN5PSI5LjI4NTcxNDMiICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiICAgICBzaG93Z3JpZD0idHJ1ZSIgICAgIHVuaXRzPSJweCIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4MCIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjIzIiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMCIgICAgIGlua3NjYXBlOm9iamVjdC1ub2Rlcz0idHJ1ZSI+ICAgIDxpbmtzY2FwZTpncmlkICAgICAgIHR5cGU9Inh5Z3JpZCIgICAgICAgaWQ9ImdyaWQxOTcxNSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGExOTE3MiI+ICAgIDxyZGY6UkRGPiAgICAgIDxjYzpXb3JrICAgICAgICAgcmRmOmFib3V0PSIiPiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+ICAgICAgICA8ZGM6dHlwZSAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4gICAgICAgIDxkYzp0aXRsZSAvPiAgICAgIDwvY2M6V29yaz4gICAgPC9yZGY6UkRGPiAgPC9tZXRhZGF0YT4gIDxnICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIgICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiICAgICBpZD0ibGF5ZXIxIiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTAzMi4zNjIyKSI+ICAgIDxwYXRoICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC41O21hcmtlcjpub25lO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiICAgICAgIGQ9Im0gNSwxMDM5LjM2MjIgMCw2IDIsMiA2LDAgMiwtMiAwLC02IC0yLC0yIC02LDAgeiBtIDMsMCA0LDAgMSwxIDAsNCAtMSwxIC00LDAgLTEsLTEgMCwtNCB6IiAgICAgICBpZD0icmVjdDc3OTciICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjY2NjY2NjY2NjIiAvPiAgICA8Y2lyY2xlICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS42MDAwMDAwMjttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBpZD0icGF0aDQzNjQiICAgICAgIGN4PSI2IiAgICAgICBjeT0iMTA0Ni4zNjIyIiAgICAgICByPSIyIiAvPiAgICA8Y2lyY2xlICAgICAgIGlkPSJwYXRoNDM2OCIgICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjYwMDAwMDAyO21hcmtlcjpub25lO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiICAgICAgIGN4PSIxNCIgICAgICAgY3k9IjEwNDYuMzYyMiIgICAgICAgcj0iMiIgLz4gICAgPGNpcmNsZSAgICAgICBpZD0icGF0aDQzNzAiICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS42MDAwMDAwMjttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBjeD0iNiIgICAgICAgY3k9IjEwMzguMzYyMiIgICAgICAgcj0iMiIgLz4gICAgPGNpcmNsZSAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjEuNjAwMDAwMDI7bWFya2VyOm5vbmU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIgICAgICAgaWQ9InBhdGg0MzcyIiAgICAgICBjeD0iMTQiICAgICAgIGN5PSIxMDM4LjM2MjIiICAgICAgIHI9IjIiIC8+ICA8L2c+PC9zdmc+); } +.mapbox-gl-draw_lasso { + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii02IC02IDMyIDMyIj48ZyB0cmFuc2Zvcm09Im1hdHJpeCguMDM5NjUgMCAwIC4wMzk2NSAxLjE2MyAxLjE2MykiIGZpbGw9IiM0ZDRkNGQiPjxwYXRoIGQ9Im0yNTAuMiA4MS42MWM5Ny40MyAwIDE3OS43NSA0My40MyAxNzkuNzUgOTQuODMgMCAxMi40NDktNC45MzQgMjQuNDQ5LTEzLjY0NSAzNS40NjVsMzUuNDAyIDEwLjQwNGM4LjYxMy0xNC4yMjcgMTMuNTMzLTI5LjYyOSAxMy41MzMtNDUuODY5IDAtNzIuOTY1LTk0LjQ2LTEzMC4xMi0yMTUuMDQtMTMwLjEyLTEyMC41NyAwLTIxNS4wNCA1Ny4xNi0yMTUuMDQgMTMwLjEyIDAgMjYuOTE4IDEyLjkzNiA1MS42NDMgMzUuMTkgNzIuMTctNi45NTEgNC41MDItMTMuNzU2IDEwLjUwMi0xOC44MzYgMTguOTg0LTEwLjQ1MyAxNy40NDktMTAuNjYgMzkuMDktLjY0NSA2NC4zNSA5LjQzMyAyMy43OTEgNy4xMjUgMzIuNTgyIDUuNjkzIDM1LjI0LTMuMzU0IDYuMzIyLTE4LjEzIDkuNTE0LTMyLjM4NSAxMi41OTYtMy40ODYuNzU4LTcuMDQgMS41MzEtMTAuNTgyIDIuMzcxLTkuNDg0IDIuMjQtMTUuMzUzIDExLjcyNS0xMy4xMyAyMS4yMyAxLjkwMiA4LjExMSA5LjE2NCAxMy41OTYgMTcuMTYgMTMuNTk2IDEuMzQgMCAyLjcwOS0uMTYgNC4wNjgtLjQ2NyAzLjMyLS43OTEgNi42NTYtMS41MTggOS45MzItMi4yMjcgMjEuMTEtNC41NjQgNDUuMDItOS43NDIgNTYuMDgtMzAuNDgyIDguNDg2LTE1LjkwMiA3LjE5NS0zNi41MTYtNC4wMy02NC44NS01LjcyNS0xNC40MzUtNi4zODUtMjUuNTY0LTEuOTQ3LTMzLjEgNC45NjUtOC40NTEgMTYuMTQtMTIuMjA3IDIyLjE5LTEzLjQ2NyAzNS43MDUgMTkuOTAyIDgyLjg1IDMyLjM1NCAxMzUuNTkgMzMuODY5bC0xMC41MDQtMzUuNzRjLTg3Ljg3LTUuNzU4LTE1OC41Ni00Ni40NS0xNTguNTYtOTQuMDcuMDAwMS01MS40IDgyLjMyLTk0LjgzIDE3OS43NS05NC44MyIvPjxwYXRoIGQ9Im00ODcuNTcgMjY5LjYzbC0yMjIuMDUtNjUuMjdjLTEuMTE1LS4zMzgtMi4yNDQtLjQ4Mi0zLjM3My0uNDgyLTMuMTEzIDAtNi4xNTggMS4yMjctOC40MzQgMy41LTMuMDk2IDMuMDgtNC4yNTggNy42MTMtMy4wMiAxMS43ODlsNjUuMjcgMjIyLjFjMS4zNCA0LjYxMyA1LjM1MiA3Ljk4MiAxMC4xNDMgOC41LjQ1My4wNDcuODkxLjA2NCAxLjMyMi4wNjQgNC4zMDkgMCA4LjMwNy0yLjMzOCAxMC40MzktNi4xNjJsNTQuMDgtOTguMDQgOTguMDMtNTQuMDljNC4yMjUtMi4zMjIgNi42MjktNi45NTEgNi4xLTExLjcyNy0uNTE0LTQuNzg3LTMuODc0LTguODA1LTguNTAyLTEwLjE3NiIvPjwvZz48L3N2Zz4=); +} .mapbox-gl-draw_line { background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjIwIiAgIGhlaWdodD0iMjAiICAgdmlld0JveD0iMCAwIDIwIDIwIiAgIGlkPSJzdmcxOTE2NyIgICB2ZXJzaW9uPSIxLjEiICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MStkZXZlbCtvc3htZW51IHIxMjkxMSIgICBzb2RpcG9kaTpkb2NuYW1lPSJsaW5lLnN2ZyI+ICA8ZGVmcyAgICAgaWQ9ImRlZnMxOTE2OSIgLz4gIDxzb2RpcG9kaTpuYW1lZHZpZXcgICAgIGlkPSJiYXNlIiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiICAgICBib3JkZXJvcGFjaXR5PSIxLjAiICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgICAgIGlua3NjYXBlOnpvb209IjE2IiAgICAgaW5rc2NhcGU6Y3g9IjEyLjg5ODc3NSIgICAgIGlua3NjYXBlOmN5PSI5LjU4OTAxNTIiICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiICAgICBzaG93Z3JpZD0idHJ1ZSIgICAgIHVuaXRzPSJweCIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4MCIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjIzIiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMCIgICAgIGlua3NjYXBlOm9iamVjdC1ub2Rlcz0idHJ1ZSI+ICAgIDxpbmtzY2FwZTpncmlkICAgICAgIHR5cGU9Inh5Z3JpZCIgICAgICAgaWQ9ImdyaWQxOTcxNSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGExOTE3MiI+ICAgIDxyZGY6UkRGPiAgICAgIDxjYzpXb3JrICAgICAgICAgcmRmOmFib3V0PSIiPiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+ICAgICAgICA8ZGM6dHlwZSAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4gICAgICAgIDxkYzp0aXRsZSAvPiAgICAgIDwvY2M6V29yaz4gICAgPC9yZGY6UkRGPiAgPC9tZXRhZGF0YT4gIDxnICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIgICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiICAgICBpZD0ibGF5ZXIxIiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTAzMi4zNjIyKSI+ICAgIDxwYXRoICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBkPSJtIDEzLjUsMTAzNS44NjIyIGMgLTEuMzgwNzEyLDAgLTIuNSwxLjExOTMgLTIuNSwyLjUgMCwwLjMyMDggMC4wNDYxNCwwLjYyNDQgMC4xNTYyNSwwLjkwNjMgbCAtMy43NSwzLjc1IGMgLTAuMjgxODM2LC0wLjExMDIgLTAuNTg1NDIxLC0wLjE1NjMgLTAuOTA2MjUsLTAuMTU2MyAtMS4zODA3MTIsMCAtMi41LDEuMTE5MyAtMi41LDIuNSAwLDEuMzgwNyAxLjExOTI4OCwyLjUgMi41LDIuNSAxLjM4MDcxMiwwIDIuNSwtMS4xMTkzIDIuNSwtMi41IDAsLTAuMzIwOCAtMC4wNDYxNCwtMC42MjQ0IC0wLjE1NjI1LC0wLjkwNjIgbCAzLjc1LC0zLjc1IGMgMC4yODE4MzYsMC4xMTAxIDAuNTg1NDIxLDAuMTU2MiAwLjkwNjI1LDAuMTU2MiAxLjM4MDcxMiwwIDIuNSwtMS4xMTkzIDIuNSwtMi41IDAsLTEuMzgwNyAtMS4xMTkyODgsLTIuNSAtMi41LC0yLjUgeiIgICAgICAgaWQ9InJlY3Q2NDY3IiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPiAgPC9nPjwvc3ZnPg==); } diff --git a/docs/API.md b/docs/API.md index 79695e808..d8dc680dc 100644 --- a/docs/API.md +++ b/docs/API.md @@ -30,7 +30,7 @@ All of the following options are optional. - `boxSelect`, boolean (default `true`): Whether or not to enable box selection of features with `shift`+`click`+drag. If `false`, `shift`+`click`+drag zooms into an area. - `clickBuffer`, number (default: `2`): Number of pixels around any feature or vertex (in every direction) that will respond to a click. - `touchBuffer`, number (default: `25`): Number of pixels around any feature of vertex (in every direction) that will respond to a touch. -- `controls`, Object: Hide or show individual controls. Each property's name is a control, and value is a boolean indicating whether the control is on or off. Available control names are `point`, `line_string`, `polygon`, `trash`, `combine_features` and `uncombine_features`. By default, all controls are on. To change that default, use `displayControlsDefault`. +- `controls`, Object: Hide or show individual controls. Each property's name is a control, and value is a boolean indicating whether the control is on or off. Available control names are `point`, `line_string`, `polygon`, `lasso`, `trash`, `combine_features` and `uncombine_features`. By default, all controls are on. To change that default, use `displayControlsDefault`. - `displayControlsDefault`, boolean (default: `true`): The default value for `controls`. For example, if you would like all controls to be *off* by default, and specify an allowed list with `controls`, use `displayControlsDefault: false`. - `styles`, Array\: An array of map style objects. By default, Draw provides a map style for you. To learn about overriding styles, see the [Styling Draw](#styling-draw) section below. - `modes`, Object: over ride the default modes with your own. `MapboxDraw.modes` can be used to see the default values. More information on custom modes [can be found here](https://github.com/mapbox/mapbox-gl-draw/blob/main/docs/MODES.md). @@ -75,6 +75,12 @@ Lets you draw a LineString feature. Lets you draw a Polygon feature. +### `draw_lasso` + +`Draw.modes.DRAW_LASSO === 'draw_lasso'` + +Lets you draw a Polygon feature with the Lasso tool. + ### `draw_point` `Draw.modes.DRAW_POINT === 'draw_point'` @@ -541,7 +547,7 @@ property | values | function --- | --- | --- meta | feature, midpoint, vertex | `midpoint` and `vertex` are used on points added to the map to communicate polygon and line handles. `feature` is used for all features. active | true, false | A feature is active when it is 'selected' in the current mode. `true` and `false` are strings. -mode | simple_select, direct_select, draw_point, draw_line_string, draw_polygon | Indicates which mode Draw is currently in. +mode | simple_select, direct_select, draw_point, draw_line_string, draw_polygon, draw_lasso | Indicates which mode Draw is currently in. Draw also provides a few more properties on features, but they should not be used for styling. For details on them, see "Using Draw with Mapbox GL JS's `queryRenderedFeatures`" below. diff --git a/src/constants.js b/src/constants.js index 14cc3516f..a565edd4e 100644 --- a/src/constants.js +++ b/src/constants.js @@ -4,6 +4,7 @@ export const classes = { CONTROL_BUTTON: 'mapbox-gl-draw_ctrl-draw-btn', CONTROL_BUTTON_LINE: 'mapbox-gl-draw_line', CONTROL_BUTTON_POLYGON: 'mapbox-gl-draw_polygon', + CONTROL_BUTTON_LASSO: 'mapbox-gl-draw_lasso', CONTROL_BUTTON_POINT: 'mapbox-gl-draw_point', CONTROL_BUTTON_TRASH: 'mapbox-gl-draw_trash', CONTROL_BUTTON_COMBINE_FEATURES: 'mapbox-gl-draw_combine', @@ -28,6 +29,7 @@ export const cursors = { }; export const types = { + LASSO: 'lasso', POLYGON: 'polygon', LINE: 'line_string', POINT: 'point' @@ -48,6 +50,7 @@ export const geojsonTypes = { export const modes = { DRAW_LINE_STRING: 'draw_line_string', DRAW_POLYGON: 'draw_polygon', + DRAW_LASSO: 'draw_lasso', DRAW_POINT: 'draw_point', SIMPLE_SELECT: 'simple_select', DIRECT_SELECT: 'direct_select', diff --git a/src/events.js b/src/events.js index 02936ac92..385cc6e9c 100644 --- a/src/events.js +++ b/src/events.js @@ -140,6 +140,8 @@ export default function(ctx) { changeMode(Constants.modes.DRAW_LINE_STRING); } else if (event.keyCode === 51 && ctx.options.controls.polygon) { changeMode(Constants.modes.DRAW_POLYGON); + } else if (event.keyCode === 83 && ctx.options.controls.lasso) { + changeMode(Constants.modes.DRAW_LASSO); } }; diff --git a/src/feature_types/lasso.js b/src/feature_types/lasso.js new file mode 100644 index 000000000..e7e620251 --- /dev/null +++ b/src/feature_types/lasso.js @@ -0,0 +1,71 @@ +import Feature from './feature'; + +const Lasso = function(ctx, geojson) { + Feature.call(this, ctx, geojson); + this.coordinates = this.coordinates.map(ring => ring.slice(0, -1)); +}; + +Lasso.prototype = Object.create(Feature.prototype); + +Lasso.prototype.isValid = function() { + if (this.coordinates.length === 0) return false; + return this.coordinates.every(ring => ring.length > 2); +}; + +// Expects valid geoJSON Lasso geometry: first and last positions must be equivalent. +Lasso.prototype.incomingCoords = function(coords) { + this.coordinates = coords.map(ring => ring.slice(0, -1)); + this.changed(); +}; + +// Does NOT expect valid geoJSON Lasso geometry: first and last positions should not be equivalent. +Lasso.prototype.setCoordinates = function(coords) { + this.coordinates = coords; + this.changed(); +}; + +Lasso.prototype.addCoordinate = function(path, lng, lat) { + this.changed(); + const ids = path.split('.').map(x => parseInt(x, 10)); + + const ring = this.coordinates[ids[0]]; + + ring.splice(ids[1], 0, [lng, lat]); +}; + +Lasso.prototype.removeCoordinate = function(path) { + this.changed(); + const ids = path.split('.').map(x => parseInt(x, 10)); + const ring = this.coordinates[ids[0]]; + if (ring) { + ring.splice(ids[1], 1); + if (ring.length < 3) { + this.coordinates.splice(ids[0], 1); + } + } +}; + +Lasso.prototype.getCoordinate = function(path) { + const ids = path.split('.').map(x => parseInt(x, 10)); + const ring = this.coordinates[ids[0]]; + return JSON.parse(JSON.stringify(ring[ids[1]])); +}; + +Lasso.prototype.getCoordinates = function() { + return this.coordinates.map(coords => coords.concat([coords[0]])); +}; + +Lasso.prototype.updateCoordinate = function(path, lng, lat) { + this.changed(); + const parts = path.split('.'); + const ringId = parseInt(parts[0], 10); + const coordId = parseInt(parts[1], 10); + + if (this.coordinates[ringId] === undefined) { + this.coordinates[ringId] = []; + } + + this.coordinates[ringId][coordId] = [lng, lat]; +}; + +export default Lasso; diff --git a/src/modes/draw_lasso.js b/src/modes/draw_lasso.js new file mode 100644 index 000000000..f42ffa7ee --- /dev/null +++ b/src/modes/draw_lasso.js @@ -0,0 +1,144 @@ +import turfSimplify from '@turf/simplify'; +import * as CommonSelectors from '../lib/common_selectors'; +import doubleClickZoom from '../lib/double_click_zoom'; +import * as Constants from '../constants'; +import isEventAtCoordinates from '../lib/is_event_at_coordinates'; +import createVertex from '../lib/create_vertex'; + +const DrawLasso = {}; + +DrawLasso.onSetup = function() { + const polygon = this.newFeature({ + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + type: Constants.geojsonTypes.POLYGON, + coordinates: [[]] + } + }); + + this.addFeature(polygon); + + this.clearSelectedFeatures(); + doubleClickZoom.disable(this); + this.updateUIClasses({ mouse: Constants.cursors.ADD }); + this.activateUIButton(Constants.types.LASSO); + this.setActionableState({ + trash: true + }); + + return { + polygon, + currentVertexPosition: 0, + toggled: false + }; +}; + +DrawLasso.clickAnywhere = function(state, e) { + if (state.currentVertexPosition > 0 && isEventAtCoordinates(e, state.polygon.coordinates[0][state.currentVertexPosition - 1])) { + return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.polygon.id] }); + } +}; + +DrawLasso.clickOnVertex = function(state) { + return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.polygon.id] }); +}; + +DrawLasso.onMouseMove = function(state, e) { + if (!state.toggled) { + return; + } + + this.updateUIClasses({ mouse: Constants.cursors.ADD }); + state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, e.lngLat.lng, e.lngLat.lat); + state.currentVertexPosition++; + state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, e.lngLat.lng, e.lngLat.lat); +}; + +DrawLasso.onTap = DrawLasso.onClick = function(state, e) { + state.toggled = !state.toggled; + if (CommonSelectors.isVertex(e)) return this.clickOnVertex(state, e); + return this.clickAnywhere(state, e); +}; + +DrawLasso.onKeyUp = function(state, e) { + if (CommonSelectors.isEscapeKey(e)) { + this.deleteFeature([state.polygon.id], { silent: true }); + this.changeMode(Constants.modes.SIMPLE_SELECT); + } else if (CommonSelectors.isEnterKey(e)) { + this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.polygon.id] }); + } +}; + +DrawLasso.onStop = function(state) { + this.updateUIClasses({ mouse: Constants.cursors.NONE }); + doubleClickZoom.enable(this); + this.activateUIButton(); + + // check to see if we've deleted this feature + if (this.getFeature(state.polygon.id) === undefined) return; + + //remove last added coordinate + state.polygon.removeCoordinate(`0.${state.currentVertexPosition}`); + if (state.polygon.isValid()) { + this.map.fire(Constants.events.CREATE, { + features: [state.polygon.toGeoJSON()] + }); + } else { + this.deleteFeature([state.polygon.id], { silent: true }); + this.changeMode(Constants.modes.SIMPLE_SELECT, {}, { silent: true }); + } +}; + +DrawLasso.toDisplayFeatures = function(state, geojson, display) { + const isActiveLasso = geojson.properties.id === state.polygon.id; + geojson.properties.active = (isActiveLasso) ? Constants.activeStates.ACTIVE : Constants.activeStates.INACTIVE; + if (!isActiveLasso) return display(geojson); + + // Don't render a polygon until it has two positions + // (and a 3rd which is just the first repeated) + if (geojson.geometry.coordinates.length === 0) return; + + const coordinateCount = geojson.geometry.coordinates[0].length; + // 2 coordinates after selecting a draw type + // 3 after creating the first point + if (coordinateCount < 3) { + return; + } + geojson.properties.meta = Constants.meta.FEATURE; + display(createVertex(state.polygon.id, geojson.geometry.coordinates[0][0], '0.0', false)); + if (coordinateCount > 3) { + // Add a start position marker to the map, clicking on this will finish the feature + // This should only be shown when we're in a valid spot + const endPos = geojson.geometry.coordinates[0].length - 3; + display(createVertex(state.polygon.id, geojson.geometry.coordinates[0][endPos], `0.${endPos}`, false)); + } + if (coordinateCount <= 4) { + // If we've only drawn two positions (plus the closer), + // make a LineString instead of a Lasso + const lineCoordinates = [ + [geojson.geometry.coordinates[0][0][0], geojson.geometry.coordinates[0][0][1]], [geojson.geometry.coordinates[0][1][0], geojson.geometry.coordinates[0][1][1]] + ]; + // create an initial vertex so that we can track the first point on mobile devices + display({ + type: Constants.geojsonTypes.FEATURE, + properties: geojson.properties, + geometry: { + coordinates: lineCoordinates, + type: Constants.geojsonTypes.LINE_STRING + } + }); + if (coordinateCount === 3) { + return; + } + } + // render the Lasso + return display(geojson); +}; + +DrawLasso.onTrash = function(state) { + this.deleteFeature([state.polygon.id], { silent: true }); + this.changeMode(Constants.modes.SIMPLE_SELECT); +}; + +export default DrawLasso; diff --git a/src/modes/index.js b/src/modes/index.js index 483ee7d26..4d7580e74 100644 --- a/src/modes/index.js +++ b/src/modes/index.js @@ -3,6 +3,7 @@ import simple_select from './simple_select'; import direct_select from './direct_select'; import draw_point from './draw_point'; import draw_polygon from './draw_polygon'; +import draw_lasso from './draw_lasso'; import draw_line_string from './draw_line_string'; export default { @@ -10,5 +11,6 @@ export default { direct_select, draw_point, draw_polygon, + draw_lasso, draw_line_string, }; diff --git a/src/options.js b/src/options.js index 720aa351a..2ed227238 100644 --- a/src/options.js +++ b/src/options.js @@ -22,6 +22,7 @@ const showControls = { point: true, line_string: true, polygon: true, + lasso: true, trash: true, combine_features: true, uncombine_features: true @@ -31,6 +32,7 @@ const hideControls = { point: false, line_string: false, polygon: false, + lasso: false, trash: false, combine_features: false, uncombine_features: false diff --git a/src/ui.js b/src/ui.js index 7add8d11c..d5fee9f35 100644 --- a/src/ui.js +++ b/src/ui.js @@ -125,6 +125,16 @@ export default function(ctx) { }); } + if (controls[Constants.types.LASSO]) { + buttonElements[Constants.types.LASSO] = createControlButton(Constants.types.LASSO, { + container: controlGroup, + className: Constants.classes.CONTROL_BUTTON_LASSO, + title: `Lasso tool ${ctx.options.keybindings ? '(s)' : ''}`, + onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_LASSO), + onDeactivate: () => ctx.events.trash() + }); + } + if (controls[Constants.types.POINT]) { buttonElements[Constants.types.POINT] = createControlButton(Constants.types.POINT, { container: controlGroup, From 61cc335d292b36d699c72c691a9aa4bbfa9ab09b Mon Sep 17 00:00:00 2001 From: Peter Bastyi Date: Wed, 30 Sep 2020 08:23:50 +0200 Subject: [PATCH 2/6] Remove accidentally added file --- src/feature_types/lasso.js | 71 -------------------------------------- 1 file changed, 71 deletions(-) delete mode 100644 src/feature_types/lasso.js diff --git a/src/feature_types/lasso.js b/src/feature_types/lasso.js deleted file mode 100644 index e7e620251..000000000 --- a/src/feature_types/lasso.js +++ /dev/null @@ -1,71 +0,0 @@ -import Feature from './feature'; - -const Lasso = function(ctx, geojson) { - Feature.call(this, ctx, geojson); - this.coordinates = this.coordinates.map(ring => ring.slice(0, -1)); -}; - -Lasso.prototype = Object.create(Feature.prototype); - -Lasso.prototype.isValid = function() { - if (this.coordinates.length === 0) return false; - return this.coordinates.every(ring => ring.length > 2); -}; - -// Expects valid geoJSON Lasso geometry: first and last positions must be equivalent. -Lasso.prototype.incomingCoords = function(coords) { - this.coordinates = coords.map(ring => ring.slice(0, -1)); - this.changed(); -}; - -// Does NOT expect valid geoJSON Lasso geometry: first and last positions should not be equivalent. -Lasso.prototype.setCoordinates = function(coords) { - this.coordinates = coords; - this.changed(); -}; - -Lasso.prototype.addCoordinate = function(path, lng, lat) { - this.changed(); - const ids = path.split('.').map(x => parseInt(x, 10)); - - const ring = this.coordinates[ids[0]]; - - ring.splice(ids[1], 0, [lng, lat]); -}; - -Lasso.prototype.removeCoordinate = function(path) { - this.changed(); - const ids = path.split('.').map(x => parseInt(x, 10)); - const ring = this.coordinates[ids[0]]; - if (ring) { - ring.splice(ids[1], 1); - if (ring.length < 3) { - this.coordinates.splice(ids[0], 1); - } - } -}; - -Lasso.prototype.getCoordinate = function(path) { - const ids = path.split('.').map(x => parseInt(x, 10)); - const ring = this.coordinates[ids[0]]; - return JSON.parse(JSON.stringify(ring[ids[1]])); -}; - -Lasso.prototype.getCoordinates = function() { - return this.coordinates.map(coords => coords.concat([coords[0]])); -}; - -Lasso.prototype.updateCoordinate = function(path, lng, lat) { - this.changed(); - const parts = path.split('.'); - const ringId = parseInt(parts[0], 10); - const coordId = parseInt(parts[1], 10); - - if (this.coordinates[ringId] === undefined) { - this.coordinates[ringId] = []; - } - - this.coordinates[ringId][coordId] = [lng, lat]; -}; - -export default Lasso; From 38d337f6a134fa36b6ff32178f2b3063696624c3 Mon Sep 17 00:00:00 2001 From: Peter Bastyi Date: Wed, 30 Sep 2020 08:41:21 +0200 Subject: [PATCH 3/6] Eliminate not yet used turf.simplify --- src/modes/draw_lasso.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modes/draw_lasso.js b/src/modes/draw_lasso.js index f42ffa7ee..042e35767 100644 --- a/src/modes/draw_lasso.js +++ b/src/modes/draw_lasso.js @@ -1,4 +1,3 @@ -import turfSimplify from '@turf/simplify'; import * as CommonSelectors from '../lib/common_selectors'; import doubleClickZoom from '../lib/double_click_zoom'; import * as Constants from '../constants'; From e895cb68622213edd3e09987820fd051dd0a770c Mon Sep 17 00:00:00 2001 From: Peter Bastyi Date: Wed, 30 Sep 2020 09:50:38 +0200 Subject: [PATCH 4/6] Simplify the polygon resulted by the lasso tool --- package.json | 1 + src/modes/draw_lasso.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/package.json b/package.json index dc3097b53..61272e384 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "@mapbox/geojson-normalize": "0.0.1", "@mapbox/geojsonhint": "3.0.0", "@mapbox/point-geometry": "0.1.0", + "@turf/simplify": "^5.1.5", "hat": "0.0.3", "lodash.isequal": "^4.2.0", "xtend": "^4.0.1" diff --git a/src/modes/draw_lasso.js b/src/modes/draw_lasso.js index 042e35767..47ac2b4ef 100644 --- a/src/modes/draw_lasso.js +++ b/src/modes/draw_lasso.js @@ -1,3 +1,5 @@ +import turfSimplify from '@turf/simplify'; + import * as CommonSelectors from '../lib/common_selectors'; import doubleClickZoom from '../lib/double_click_zoom'; import * as Constants from '../constants'; @@ -56,6 +58,24 @@ DrawLasso.onMouseMove = function(state, e) { DrawLasso.onTap = DrawLasso.onClick = function(state, e) { state.toggled = !state.toggled; + if (!state.toggled) { + // We have just finished drawing with lasso + let tolerance = (3 / ((this.map.getZoom() - 4) * 150)) - 0.001; // https://www.desmos.com/calculator/b3zi8jqskw + if (tolerance < 0 || !(isFinite(tolerance))) { + // Tolerance cannot be negative + tolerance = 0; + } + + // Simplify the polygon because mouseMove events result in tons of points that build up the resulting polygon + turfSimplify(state.polygon, { + tolerance, + mutate: true, + highQuality: true + }); + this.fireUpdate(); + + this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.polygon.id] }); + } if (CommonSelectors.isVertex(e)) return this.clickOnVertex(state, e); return this.clickAnywhere(state, e); }; @@ -140,4 +160,12 @@ DrawLasso.onTrash = function(state) { this.changeMode(Constants.modes.SIMPLE_SELECT); }; + +DrawLasso.fireUpdate = function() { + this.map.fire(Constants.events.UPDATE, { + action: Constants.updateActions.MOVE, + features: this.getSelected().map(f => f.toGeoJSON()) + }); +}; + export default DrawLasso; From ca7cf3e89c57057639d3e24d9befaeb22a2fae82 Mon Sep 17 00:00:00 2001 From: Peter Bastyi Date: Wed, 30 Sep 2020 16:54:25 +0200 Subject: [PATCH 5/6] Update yarn.lock --- yarn.lock | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/yarn.lock b/yarn.lock index 445438fc2..29ada45c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -877,6 +877,21 @@ "@turf/helpers" "6.x" "@turf/meta" "6.x" +"@turf/clean-coords@^5.1.5": + version "5.1.5" + resolved "https://registry.yarnpkg.com/@turf/clean-coords/-/clean-coords-5.1.5.tgz#12800a98a78c9a452a72ec428493c43acf2ada1f" + integrity sha1-EoAKmKeMmkUqcuxChJPEOs8q2h8= + dependencies: + "@turf/helpers" "^5.1.5" + "@turf/invariant" "^5.1.5" + +"@turf/clone@^5.1.5": + version "5.1.5" + resolved "https://registry.yarnpkg.com/@turf/clone/-/clone-5.1.5.tgz#253e8d35477181976e33adfab50a0f02a7f0e367" + integrity sha1-JT6NNUdxgZduM636tQoPAqfw42c= + dependencies: + "@turf/helpers" "^5.1.5" + "@turf/combine@^3.14.0": version "3.14.0" resolved "https://registry.yarnpkg.com/@turf/combine/-/combine-3.14.0.tgz#d6aa15e20c7a217bf4dd19f0347ec848135cf222" @@ -894,6 +909,18 @@ resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-3.13.0.tgz#d06078a1464cf56cdb7ea624ea1e13a71b88b806" integrity sha1-0GB4oUZM9WzbfqYk6h4TpxuIuAY= +"@turf/helpers@^5.1.5": + version "5.1.5" + resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-5.1.5.tgz#153405227ab933d004a5bb9641a9ed999fcbe0cf" + integrity sha1-FTQFInq5M9AEpbuWQantmZ/L4M8= + +"@turf/invariant@^5.1.5": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@turf/invariant/-/invariant-5.2.0.tgz#f0150ff7290b38577b73d088b7932c1ee0aa90a7" + integrity sha1-8BUP9ykLOFd7c9CIt5MsHuCqkKc= + dependencies: + "@turf/helpers" "^5.1.5" + "@turf/meta@6.x": version "6.0.2" resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-6.0.2.tgz#eb92951126d24a613ac1b7b99d733fcc20fd30cf" @@ -906,6 +933,23 @@ resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-3.14.0.tgz#8d3050c1a0f44bf406a633b6bd28c510f7bcee27" integrity sha1-jTBQwaD0S/QGpjO2vSjFEPe87ic= +"@turf/meta@^5.1.5": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-5.2.0.tgz#3b1ad485ee0c3b0b1775132a32c384d53e4ba53d" + integrity sha1-OxrUhe4MOwsXdRMqMsOE1T5LpT0= + dependencies: + "@turf/helpers" "^5.1.5" + +"@turf/simplify@^5.1.5": + version "5.1.5" + resolved "https://registry.yarnpkg.com/@turf/simplify/-/simplify-5.1.5.tgz#0ac8f27a2eb4218183edd9998c3275abe408b926" + integrity sha1-Csjyei60IYGD7dmZjDJ1q+QIuSY= + dependencies: + "@turf/clean-coords" "^5.1.5" + "@turf/clone" "^5.1.5" + "@turf/helpers" "^5.1.5" + "@turf/meta" "^5.1.5" + "@turf/union@^3.0.10": version "3.14.0" resolved "https://registry.yarnpkg.com/@turf/union/-/union-3.14.0.tgz#0a79180aeacf9c23c45b568a273e8bef02bc078f" From 45c005f465b6dc82698c0f721b5a24f082e9b125 Mon Sep 17 00:00:00 2001 From: Peter Bastyi Date: Mon, 5 Oct 2020 15:05:29 +0200 Subject: [PATCH 6/6] Fix failing unit tests --- test/api.test.js | 2 +- test/options.test.js | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/test/api.test.js b/test/api.test.js index a67732f37..77fd059bb 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -418,7 +418,7 @@ test('Draw.modes', (t) => { t.equal(Draw.modes.DRAW_LINE_STRING, Constants.modes.DRAW_LINE_STRING, 'draw_line_string'); t.equal(Draw.modes.DRAW_POLYGON, Constants.modes.DRAW_POLYGON, 'draw_polygon'); t.equal(Draw.modes.STATIC, Constants.modes.STATIC, 'static'); - t.equal(getPublicMemberKeys(Draw.modes).length, 6, 'no unexpected modes'); + t.equal(getPublicMemberKeys(Draw.modes).length, 7, 'no unexpected modes'); t.end(); }); diff --git a/test/options.test.js b/test/options.test.js index c4669eb67..b0c819607 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -22,6 +22,7 @@ test('Options test', (t) => { point: true, line_string: true, polygon: true, + lasso: true, trash: true, combine_features: true, uncombine_features: true @@ -49,6 +50,7 @@ test('Options test', (t) => { point: true, line_string: true, polygon: true, + lasso: true, trash: true, combine_features: true, uncombine_features: true @@ -76,6 +78,7 @@ test('Options test', (t) => { point: false, line_string: false, polygon: false, + lasso: false, trash: false, combine_features: false, uncombine_features: false @@ -102,6 +105,7 @@ test('Options test', (t) => { point: true, line_string: false, polygon: false, + lasso: false, trash: false, combine_features: false, uncombine_features: false @@ -129,6 +133,7 @@ test('Options test', (t) => { point: false, line_string: true, polygon: true, + lasso: true, trash: true, combine_features: true, uncombine_features: true @@ -156,6 +161,7 @@ test('Options test', (t) => { point: true, line_string: true, polygon: true, + lasso: true, trash: true, combine_features: true, uncombine_features: true