I am working on utilize snapping with the Sketch widget in 2D. It also takes advantage of the Magnifier to make it easier to snap to the vertices of existing graphics.
For me the snapping and editing widget is working fine and have no issue. Further I want to add the magnifier, to my code, I try some code to add but not getting successful. Below is my code.
Any suggestion?
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.21/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.21/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#configurationDiv {
padding: 10px;
text-align: left;
width: 250px;
}
.switch {
position: relative;
display: inline-block;
width: 45px;
height: 22px;
vertical-align: middle;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: 0.4s;
transition: 0.4s;
}
.slider:before {
position: absolute;
content: "";
height: 20px;
width: 20px;
left: 3px;
bottom: 1px;
background-color: white;
-webkit-transition: 0.4s;
transition: 0.4s;
}
input:checked .slider {
background-color: #2196f3;
}
input:focus .slider {
box-shadow: 0 0 1px #2196f3;
}
input:checked .slider:before {
-webkit-transform: translateX(20px);
-ms-transform: translateX(20px);
transform: translateX(20px);
}
/* Rounded sliders */
.slider.round {
border-radius: 20px;
}
.slider.round:before {
border-radius: 50%;
}
.labelText {
padding-left: 5px;
font-size: 15px;
}
#mainDiv {
padding: 8px;
}
</style>
<script>
require([
"esri/widgets/Sketch",
"esri/Map",
"esri/layers/GraphicsLayer",
"esri/views/MapView",
"esri/widgets/Expand"
], (Sketch, Map, GraphicsLayer, MapView, Expand) => {
// Get reference to div elements
const magnifierSlider = document.getElementById("magnifierCheckbox");
const labelText = document.getElementById("labelText");
const selfSnapCheckBox = document.getElementById(
"selfSnappingCheckbox"
);
const featureSnapCheckBox = document.getElementById(
"featureSnappingCheckbox"
);
let toggle;
const graphicsLayer = new GraphicsLayer();
const map = new Map({
basemap: "streets-navigation-vector",
layers: [graphicsLayer]
});
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 6,
center: [38.33081, 0.36532]
});
const sketch = new Sketch({
layer: graphicsLayer,
view: view,
// graphic will be selected as soon as it is created
creationMode: "update",
snappingOptions: {
// autocasts as SnappingOptions()
enabled: true, // snapping will be on by default
// feature snapping will be enabled on the GraphicsLayer
featureSources: [{ layer: graphicsLayer }]
}
});
const configurationExpand = new Expand({
expandIconClass: "esri-icon-settings2",
expandTooltip: "Show snapping configuration",
expanded: true,
view: view,
content: document.getElementById("configurationDiv")
});
view.when(() => {
// add the ui components to the view
view.ui.add(sketch, "top-right");
view.ui.add(configurationExpand, "bottom-right");
// Magnifier
view.magnifier.visible = false;
view.magnifier.factor = 1.7; // magnification factor
view.magnifier.size = 150; // magnifier image size
view.magnifier.offset = { x: 75, y: 75 }; // x and y offset values
view.on("pointer-move", (evt) => {
view.magnifier.position = { x: evt.x, y: evt.y };
});
view.on(["key-down", "key-up"], (event) => {
if (event.type === "key-down" && event.key === "m") {
view.magnifier.visible = toggle ? false : true;
}
if (event.type === "key-up" && event.key === "m") {
view.magnifier.visible = toggle ? true : false;
}
magnifierSlider.checked = view.magnifier.visible;
});
});
// event listeners to toggle the Magnifier as well
// as the individual snapping functionality like self and feature snapping.
magnifierSlider.onchange = () => {
toggleMagnifier();
};
selfSnapCheckBox.checked = sketch.snappingOptions.selfEnabled;
selfSnapCheckBox.addEventListener("change", (event) => {
sketch.snappingOptions.selfEnabled = event.target.checked
? true
: false;
});
featureSnapCheckBox.checked = sketch.snappingOptions.featureEnabled;
featureSnapCheckBox.addEventListener("change", (event) => {
sketch.snappingOptions.featureEnabled = event.target.checked
? true
: false;
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="configurationDiv" class="esri-widget">
<h3>Toggle SnappingOptions</h3>
<table id="configurationTable">
<tr>
<td>
<label for="selfSnappingCheckbox" id="selfSnappingCheckboxLabel">
- self snapping</label
>
</td>
<td><input type="checkbox" id="selfSnappingCheckbox" /></td>
</tr>
<tr>
<td>
<label
for="featureSnappingCheckbox"
id="featureSnappingCheckboxLabel"
>
- feature snapping</label
>
</td>
<td><input type="checkbox" id="featureSnappingCheckbox" /></td>
</tr>
</table>
<hr />
<div id="mainDiv" class="esri-widget">
<label class="switch">
<input id="magnifierCheckbox" type="checkbox" />
<span class="slider round"></span>
</label>
<label class="labelText" id="labelText">Magnifier</label>
<p>
<i>Hold down the <b>'m'</b> key to toggle the Magnifier</i>
</p>
</div>
</div>
</body>
</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
If I understand correctly the idea,
- if magnifier checkbox is checked then while
m
key is pressed magnifier widget is shown.
Then you just need a couple of twist to the code,
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="stylesheet" href="https://js.arcgis.com/4.21/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.21/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#configurationDiv {
padding: 10px;
text-align: left;
width: 250px;
}
.switch {
position: relative;
display: inline-block;
width: 45px;
height: 22px;
vertical-align: middle;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: 0.4s;
transition: 0.4s;
}
.slider:before {
position: absolute;
content: "";
height: 20px;
width: 20px;
left: 3px;
bottom: 1px;
background-color: white;
-webkit-transition: 0.4s;
transition: 0.4s;
}
input:checked .slider {
background-color: #2196f3;
}
input:focus .slider {
box-shadow: 0 0 1px #2196f3;
}
input:checked .slider:before {
-webkit-transform: translateX(20px);
-ms-transform: translateX(20px);
transform: translateX(20px);
}
/* Rounded sliders */
.slider.round {
border-radius: 20px;
}
.slider.round:before {
border-radius: 50%;
}
.labelText {
padding-left: 5px;
font-size: 15px;
}
#mainDiv {
padding: 8px;
}
</style>
<script>
require([
"esri/widgets/Sketch",
"esri/Map",
"esri/layers/GraphicsLayer",
"esri/views/MapView",
"esri/widgets/Expand"
], (Sketch, Map, GraphicsLayer, MapView, Expand) => {
// Get reference to div elements
const magnifierSlider = document.getElementById("magnifierCheckbox");
const labelText = document.getElementById("labelText");
const selfSnapCheckBox = document.getElementById(
"selfSnappingCheckbox"
);
const featureSnapCheckBox = document.getElementById(
"featureSnappingCheckbox"
);
let toggle;
const graphicsLayer = new GraphicsLayer();
const map = new Map({
basemap: "streets-navigation-vector",
layers: [graphicsLayer]
});
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 6,
center: [38.33081, 0.36532]
});
const sketch = new Sketch({
layer: graphicsLayer,
view: view,
// graphic will be selected as soon as it is created
creationMode: "update",
snappingOptions: {
// autocasts as SnappingOptions()
enabled: true, // snapping will be on by default
// feature snapping will be enabled on the GraphicsLayer
featureSources: [{ layer: graphicsLayer }]
}
});
const configurationExpand = new Expand({
expandIconClass: "esri-icon-settings2",
expandTooltip: "Show snapping configuration",
expanded: true,
view: view,
content: document.getElementById("configurationDiv")
});
view.when(() => {
// add the ui components to the view
view.ui.add(sketch, "top-right");
view.ui.add(configurationExpand, "bottom-right");
// Magnifier
view.magnifier.visible = false;
view.magnifier.factor = 1.7; // magnification factor
view.magnifier.size = 150; // magnifier image size
view.magnifier.offset = { x: 75, y: 75 }; // x and y offset values
view.on("pointer-move", (evt) => {
view.magnifier.position = { x: evt.x, y: evt.y };
});
view.on(["key-down", "key-up"], (event) => {
if (toggle) { // magnifierSlider is checked?
if (event.type === "key-down" && event.key === "m") {
view.magnifier.visible = true;
}
if (event.type === "key-up" && event.key === "m") {
view.magnifier.visible = false;
}
}
// magnifierSlider.checked = view.magnifier.visible;
});
});
// event listeners to toggle the Magnifier as well
// as the individual snapping functionality like self and feature snapping.
magnifierSlider.onchange = () => {
toggle = magnifierSlider.checked;
};
selfSnapCheckBox.checked = sketch.snappingOptions.selfEnabled;
selfSnapCheckBox.addEventListener("change", (event) => {
sketch.snappingOptions.selfEnabled = event.target.checked
? true
: false;
});
featureSnapCheckBox.checked = sketch.snappingOptions.featureEnabled;
featureSnapCheckBox.addEventListener("change", (event) => {
sketch.snappingOptions.featureEnabled = event.target.checked
? true
: false;
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="configurationDiv" class="esri-widget">
<h3>Toggle SnappingOptions</h3>
<table id="configurationTable">
<tr>
<td>
<label for="selfSnappingCheckbox" id="selfSnappingCheckboxLabel">
- self snapping</label>
</td>
<td><input type="checkbox" id="selfSnappingCheckbox" /></td>
</tr>
<tr>
<td>
<label for="featureSnappingCheckbox" id="featureSnappingCheckboxLabel">
- feature snapping</label>
</td>
<td><input type="checkbox" id="featureSnappingCheckbox" /></td>
</tr>
</table>
<hr />
<div id="mainDiv" class="esri-widget">
<label class="switch">
<input id="magnifierCheckbox" type="checkbox" />
<span class="slider round"></span>
</label>
<label class="labelText" id="labelText">Magnifier</label>
<p>
<i>Hold down the <b>'m'</b> key to toggle the Magnifier</i>
</p>
</div>
</div>
</body>
</html>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
You can achieve this by defining the magnifier function in your code, as follows:
function toggleMagnifier() {
toggle = !toggle;
view.magnifier.visible = toggle;
view.focus();
}
So your final code will look like this:
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<title>
Snapping with Sketch widget and Magnifier | Sample | ArcGIS API for
JavaScript 4.21
</title>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.21/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.21/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#configurationDiv {
padding: 10px;
text-align: left;
width: 250px;
}
.switch {
position: relative;
display: inline-block;
width: 45px;
height: 22px;
vertical-align: middle;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: 0.4s;
transition: 0.4s;
}
.slider:before {
position: absolute;
content: "";
height: 20px;
width: 20px;
left: 3px;
bottom: 1px;
background-color: white;
-webkit-transition: 0.4s;
transition: 0.4s;
}
input:checked .slider {
background-color: #2196f3;
}
input:focus .slider {
box-shadow: 0 0 1px #2196f3;
}
input:checked .slider:before {
-webkit-transform: translateX(20px);
-ms-transform: translateX(20px);
transform: translateX(20px);
}
/* Rounded sliders */
.slider.round {
border-radius: 20px;
}
.slider.round:before {
border-radius: 50%;
}
.labelText {
padding-left: 5px;
font-size: 15px;
}
#mainDiv {
padding: 8px;
}
</style>
<script>
require([
"esri/widgets/Sketch",
"esri/Map",
"esri/layers/GraphicsLayer",
"esri/views/MapView",
"esri/widgets/Expand"
], (Sketch, Map, GraphicsLayer, MapView, Expand) => {
// Get reference to div elements
const magnifierSlider = document.getElementById("magnifierCheckbox");
const labelText = document.getElementById("labelText");
const selfSnapCheckBox = document.getElementById(
"selfSnappingCheckbox"
);
const featureSnapCheckBox = document.getElementById(
"featureSnappingCheckbox"
);
let toggle;
const graphicsLayer = new GraphicsLayer();
const map = new Map({
basemap: "streets-navigation-vector",
layers: [graphicsLayer]
});
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 6,
center: [38.33081, 0.36532]
});
const sketch = new Sketch({
layer: graphicsLayer,
view: view,
// graphic will be selected as soon as it is created
creationMode: "update",
snappingOptions: {
// autocasts as SnappingOptions()
enabled: true, // snapping will be on by default
// feature snapping will be enabled on the GraphicsLayer
featureSources: [{ layer: graphicsLayer }]
}
});
const configurationExpand = new Expand({
expandIconClass: "esri-icon-settings2",
expandTooltip: "Show snapping configuration",
expanded: true,
view: view,
content: document.getElementById("configurationDiv")
});
view.when(() => {
// add the ui components to the view
view.ui.add(sketch, "top-right");
view.ui.add(configurationExpand, "bottom-right");
// Magnifier
view.magnifier.visible = false;
view.magnifier.factor = 1.7; // magnification factor
view.magnifier.size = 150; // magnifier image size
view.magnifier.offset = { x: 75, y: 75 }; // x and y offset values
// displays the Magnifier wherever the cursor appears on the Map
view.on("pointer-move", (evt) => {
view.magnifier.position = { x: evt.x, y: evt.y };
});
// adding a shortcut key to toggle the Magnifier visibility. Use the 'm' key
view.on(["key-down", "key-up"], (event) => {
if (event.type === "key-down" && event.key === "m") {
view.magnifier.visible = toggle ? false : true;
}
if (event.type === "key-up" && event.key === "m") {
view.magnifier.visible = toggle ? true : false;
}
magnifierSlider.checked = view.magnifier.visible;
});
});
// event listeners to toggle the Magnifier as well
// as the individual snapping functionality like self and feature snapping.
magnifierSlider.onchange = () => {
toggleMagnifier();
};
selfSnapCheckBox.checked = sketch.snappingOptions.selfEnabled;
selfSnapCheckBox.addEventListener("change", (event) => {
sketch.snappingOptions.selfEnabled = event.target.checked
? true
: false;
});
featureSnapCheckBox.checked = sketch.snappingOptions.featureEnabled;
featureSnapCheckBox.addEventListener("change", (event) => {
sketch.snappingOptions.featureEnabled = event.target.checked
? true
: false;
});
// toggle the Magnifier visibility
function toggleMagnifier() {
toggle = !toggle;
view.magnifier.visible = toggle;
view.focus(); // focus back to the view to listen for 'm' key
}
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="configurationDiv" class="esri-widget">
<h3>Toggle SnappingOptions</h3>
<table id="configurationTable">
<tr>
<td>
<label for="selfSnappingCheckbox" id="selfSnappingCheckboxLabel">
- self snapping</label
>
</td>
<td><input type="checkbox" id="selfSnappingCheckbox" /></td>
</tr>
<tr>
<td>
<label
for="featureSnappingCheckbox"
id="featureSnappingCheckboxLabel"
>
- feature snapping</label
>
</td>
<td><input type="checkbox" id="featureSnappingCheckbox" /></td>
</tr>
</table>
<hr />
<div id="mainDiv" class="esri-widget">
<label class="switch">
<input id="magnifierCheckbox" type="checkbox" />
<span class="slider round"></span>
</label>
<label class="labelText" id="labelText">Magnifier</label>
<p>
<i>Hold down the <b>'m'</b> key to toggle the Magnifier</i>
</p>
</div>
</div>
</body>
</html>
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>