How to print a specific extent of an ArcGis Map? - gis

I'm trying to print a specific zone on an Arcgis maps with the JS API (not the extend that is displayed).
I didn't find any method or option to do this so I tried to change the extend and then print the map :
var extent = new esri.geometry.Extent(
-620526.0922336339,
5993991.149960931,
108988.90572005256,
6293624.300838808,
myMap.spatialReference
);
myMap.setExtent(extent, true).then(function() {
console.log('setExtend is finished');
var template = new esri.tasks.PrintTemplate();
template.exportOptions = {
width : 500,
height : 500
};
template.format = 'jpg';
template.layout = 'MAP_ONLY';
var params = new esri.tasks.PrintParameters();
params.map = myMap;
params.template = template;
var printTask = new esri.tasks.PrintTask(urlToThePrintServer);
printTask.execute(params);
});
Since setExtent is asynchonous and return a defered I have to use the 'then' method.
I can see the map moving but the defered doesn't seem to works ... (I don't see the console.log()).
is there another way to print a specific extend of a map ?
if not why is the 'then' method never called ?
(I'm using the 3.12 JS API)

Your code looks good to me, though obviously you didn't post all your JavaScript or any of your HTML. Maybe you're not requiring the modules you need. Or maybe your code is trying to run before the map is loaded, though that's unlikely because as you say, the map does move. Or maybe something else is wrong.
I put a full working example at http://jsfiddle.net/06jtccx0/ . Hopefully you can compare that to what you're doing and figure out what is wrong with your code. Here's the same code for your convenience:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
<title>Simple Map</title>
<link rel="stylesheet" href="http://js.arcgis.com/3.13/esri/css/esri.css">
<style>
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
background-color: #FFF;
overflow: hidden;
font-family: "Trebuchet MS";
}
</style>
<script src="http://js.arcgis.com/3.13/"></script>
<script>
var myMap;
var urlToThePrintServer = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task";
require(["esri/map", "dojo/domReady!"], function(Map) {
myMap = new Map("map", {
basemap: "topo", //For full list of pre-defined basemaps, navigate to http://arcg.is/1JVo6Wd
center: [-122.45, 37.75], // longitude, latitude
zoom: 13
});
myMap.on("load", function(map) {
var extent = new esri.geometry.Extent(
-620526.0922336339,
5993991.149960931,
108988.90572005256,
6293624.300838808,
myMap.spatialReference
);
myMap.setExtent(extent, true).then(function() {
console.log('setExtend is finished');
require([
"esri/tasks/PrintTemplate",
"esri/tasks/PrintParameters",
"esri/tasks/PrintTask"
], function(
PrintTemplate,
PrintParameters,
PrintTask
) {
var template = new PrintTemplate();
template.exportOptions = {
width : 500,
height : 500
};
template.format = 'jpg';
template.layout = 'MAP_ONLY';
var params = new PrintParameters();
params.map = myMap;
params.template = template;
var printTask = new PrintTask(urlToThePrintServer);
printTask.execute(params, function(response) {
console.log("The printed document is at " + response.url);
window.open(response.url);
});
});
});
});
});
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>

Related

Clear canvas drawpad jquery

I'm using the drawing pad (pen tool) plugin of Jquery to draw with different colors and having an image in the canvas as background. My purpose is to have a button to clear the drawing over the canvas. The way I try to do it remove the background image along with the drawing. How can I keep the background and remove the drawing on clicking the clear button ?
My fiddle : https://jsfiddle.net/ub3s9go7/
<script>
$(document).ready(function() {
// set background
var urlBackground = 'https://picsum.photos/id/100/500/400';
var imageBackground = new Image();
imageBackground.src = urlBackground;
imageBackground.setAttribute('crossorigin', 'anonymous');
$("#target").drawpad();
var contextCanvas = $("#target canvas").get(0).getContext('2d');
imageBackground.onload = function(){
contextCanvas.drawImage(imageBackground, 0, 0);
}
// Need to clear only the drawing not the background image
$("#clearDrawing").click(function() {
contextCanvas.clearRect(0, 0, 750, 423);
});
});
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cnbilgin.github.io/jquery-drawpad/jquery-drawpad.css" />
<style>
body {background-color:rgb(248, 255, 227)}
#target {
width:500px;
height:400px;
}
</style>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cnbilgin.github.io/jquery-drawpad/jquery-drawpad.js"></script>
</head>
<body>
<button id="clearDrawing">Clear Drawing</button>
<div id="target" class="drawpad-dashed"></div>
</body>
</html>
This answer is an improvisation on my previous answer at https://stackoverflow.com/a/67155647/3706717
So we have new requirement: delete/clear previous drawings
There are some possible approach here:
#sinisake in comment suggested to reload the background so that we have fresh canvas with only the background intact (but for some reason, white doodle make the background gone)
the library must have "delete" or "erase" doodle feature (which it didn't have)
save each changes of the drawing when user click "save", so that user can "undo" to previous version of the drawing (like git's git commit and git reset command), I'll be using this approach in my answer
Ideally, you should use server-side language and persistent storage (e.g.: database) to store user's doodling history. But in this case, to simulate such thing I'll be using javascript's localStorage API https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
So every time I'm calling localStorage API, just assume that I'm calling some ajax to some endpoint.
Fiddle: https://jsfiddle.net/0da572jy/3/
Here is stack fiddle (modified because browser didn't allow stack fiddle to use localStorage)
// polyfill for localStorage API
var localStorage1 = {
items: {},
removeItem: function(key) {
window.localStorage1.items[key] = null;
},
getItem: function(key) {
return window.localStorage1.items[key];
},
setItem: function(key, val) {
return window.localStorage1.items[key] = val;
},
}
//window.localStorage = localStorage1;
window.localStorage1 = localStorage1;
$(document).ready(function() {
$("#save").click(function() {
// I already explained the #save logic in https://stackoverflow.com/a/67155647/3706717
//console.log("save");
var base64Image = $("#target canvas").get(0).toDataURL();
//console.log(base64Image);
$("#outputBase64FormInput").val(base64Image);
$("#outputBase64").html(base64Image);
// load/read saved states/histories
var savedImageJson = window.localStorage1.getItem("savedImage");
//console.log(savedImageJson);
// if the history is undefined, create empty array
if(savedImageJson == null || typeof savedImageJson == "undefined") savedImageJson = "[]";
// parse the history
var savedImageArr = JSON.parse(savedImageJson);
// add current state as a new item to history
savedImageArr.push(base64Image);
// save the modified (added history)
window.localStorage1.setItem("savedImage", JSON.stringify(savedImageArr));
$("#numOfSavedHistory").html( savedImageArr.length );
});
// clear button just clears the localStorage (or any kind of API you use for persistent storage
$("#clear").click(function() {
//console.log("save");
window.localStorage1.removeItem("savedImage");
$("#numOfSavedHistory").html( 0 );
});
// undo last change (rollback to last state when you clicked save)
$("#undo").click(function() {
// clear canvas (to prevent white ink bug that also clears the background)
canvas.width = canvas.width;
//console.log("undo");
// load/read saved states/histories
var savedImageJson = window.localStorage1.getItem("savedImage");
//console.log(savedImageJson);
// if the history is undefined, create empty array
if(savedImageJson == null || typeof savedImageJson == "undefined") savedImageJson = "[]";
// parse the history
var savedImageArr = JSON.parse(savedImageJson);
// delete last item in history
savedImageArr.pop();
// save the modified (pop'ed history)
window.localStorage1.setItem("savedImage", JSON.stringify(savedImageArr));
// draw old picture on canvas
var imageOld = new Image();
imageOld.src = savedImageArr[savedImageArr.length-1];
imageOld.onload = function() {
contextCanvas.drawImage(imageOld, 0, 0);
};
$("#numOfSavedHistory").html( savedImageArr.length );
});
// set background
var urlBackground = 'https://picsum.photos/id/100/500/400';
var imageBackground = new Image();
imageBackground.src = urlBackground;
//imageBackground.crossorigin = "anonymous";
imageBackground.setAttribute('crossorigin', 'anonymous');
$("#target").drawpad();
var canvas = $("#target canvas").get(0);
var contextCanvas = canvas.getContext('2d');
imageBackground.onload = function(){
contextCanvas.drawImage(imageBackground, 0, 0);
$("#clear").trigger("click"); // clear previous drawings when page refreshed
$("#save").trigger("click"); // save the first image (background only)
}
});
body {background-color:rgb(248, 255, 227)}
#target {
width:500px;
height:400px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cnbilgin.github.io/jquery-drawpad/jquery-drawpad.css" />
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cnbilgin.github.io/jquery-drawpad/jquery-drawpad.js"></script>
</head>
<body>
<button id="undo">Undo</button>
<button id="save">Save</button>
<button id="clear">Clear Saved Picture</button>
<span id="numOfSavedHistory">0</span>
<div id="target" class="drawpad-dashed"></div>
<div id="outputBase64"></div>
</body>
</html>

Here maps not draggable in ms access webbrowser

I have created a simple html using the draggable marker example from here maps. I have adapted it to support IE 11 by adding reference to legacy js, meta tag and using P2D engine in map options. Also added two url parameters for coordinates. It works perfectly in IE11 and it loads and shows pan and zoom buttons in ms-access webbrowser but it keeps static, it's not draggable, but pan and zoom works.
The curious thing is that if I navigate to wego.here.com in the same webbrowser control then the map is draggable. So they're doing something else in the here maps main page that I'm not doing in my script.
I have also tried using Microsoft Web Browser from the activex controls list in access.
I need it to be draggable so I can pick the coordinates after the user changes the marker position.
This is my script:
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Draggable Marker</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="stylesheet" type="text/css" href="https://js.api.here.com/v3/3.1/mapsjs-ui.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-core.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-core-legacy.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-service.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-service-legacy.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-ui.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js" type="text/javascript" charset="utf-8"></script>
<style>
html, body { margin:0px; padding:0px; width: 100%; height: 100%; }
.main { height: 100%; }
</style>
</head>
<body id="markers-on-the-map">
<div class="main" style="width:100%" id="map"></div>
<input type="hidden" id="long" name="long">
<input type="hidden" id="lat" name="lat">
<script>
function addDraggableMarker(map, behavior){
var marker = new H.map.Marker({lat:latitud, lng:longitud}, {volatility: true});
// Ensure that the marker can receive drag events
marker.draggable = true;
map.addObject(marker);
// disable the default draggability of the underlying map
// and calculate the offset between mouse and target's position
// when starting to drag a marker object:
map.addEventListener('dragstart', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
var targetPosition = map.geoToScreen(target.getGeometry());
target['offset'] = new H.math.Point(pointer.viewportX - targetPosition.x, pointer.viewportY - targetPosition.y);
behavior.disable();
}
}, false);
// re-enable the default draggability of the underlying map
// when dragging has completed
map.addEventListener('dragend', function(ev) {
var target = ev.target;
if (target instanceof H.map.Marker) {
$('#long').val(ev.target.b.lng);
$('#lat').val(ev.target.b.lat);
behavior.enable();
}
}, false);
// Listen to the drag event and move the position of the marker
// as necessary
map.addEventListener('drag', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
target.setGeometry(map.screenToGeo(pointer.viewportX - target['offset'].x, pointer.viewportY - target['offset'].y));
}
}, false);
}
/**
* Boilerplate map initialization code starts below:
*/
//Step 1: initialize communication with the platform
// In your own code, replace variable window.apikey with your own apikey
var platform = new H.service.Platform({
apikey: '?????????????????????????????????'
});
var defaultLayers = platform.createDefaultLayers();
//url parameters
var query_string = {};
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if (typeof query_string[pair[0]] === "undefined") {
query_string[pair[0]] = decodeURIComponent(pair[1]);
} else if (typeof query_string[pair[0]] === "string") {
var arr = [ query_string[pair[0]],decodeURIComponent(pair[1]) ];
query_string[pair[0]] = arr;
} else {
query_string[pair[0]].push(decodeURIComponent(pair[1]));
}
}
var latitud=query_string.lat;
var longitud=query_string.long;
//Step 2: initialize a map - this map is centered over Boston
var map = new H.Map(document.getElementById('map'),
defaultLayers.raster.normal.map, {
center: {lat:latitud, lng:longitud},
engineType: H.map.render.RenderEngine.EngineType.P2D,
zoom: 12,
pixelRatio: window.devicePixelRatio || 1
});
// add a resize listener to make sure that the map occupies the whole container
//window.addEventListener('resize', () => map.getViewPort().resize());
window.addEventListener('resize', function () {map.getViewPort().resize(); });
//Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
//var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Step 4: Create the default UI:
var ui = H.ui.UI.createDefault(map, defaultLayers, 'en-US');
// Add the click event listener.
addDraggableMarker(map, behavior);
</script>
</body>
</html>```
Check please on this static page
: your code works for my IE11

Google Maps JS API with KML layer control

I have found different solutions for switching KmlLayers on/off using JavaScript. All scripts that I've seen require separate functions for each layer, but I want to have only one function for all layers so when adding a new layer to my web page I don't have to edit the existing JavaScript code.
My code:
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
<style type="text/css">
* {margin:0; padding:0; border:0; outline:0; font-size:100%;
vertical-align:baseline}
html, body {width:100%; height:100%}
#map {width:100%; height:95%}
</style>
<script type="text/javascript"
src="http://maps.googleapis.com/maps/api/js?sensor=false&language=lv">
</script>
<script type="text/javascript">
var G = google.maps; var kml = null; var show = false;
function toggle() {
var tr = this.rel;
if (!tr) {
tr = new G.KmlLayer('http://www.eiranet.lv/kartes/Anjo/kmz/' +
this.id + '.kmz', {preserveViewport:true})
};
show = !show;
if (show) {
tr.setMap(map)
}
else {
tr.setMap(null)
};
};
function initialize() {
var layers = document.getElementsByTagName('input');
var options = {
center: new G.LatLng(34.9, 137.3),
zoom: 10,
mapTypeId: G.MapTypeId.TERRAIN,
scaleControl: true,
overviewMapControl: true,
mapTypeControlOptions: {
style:G.MapTypeControlStyle.DROPDOWN_MENU }
};
map = new G.Map(document.getElementById('map'), options);
for (var i=0; i<layers.length; i++) {
layers[i].type = 'checkbox';
G.event.addDomListener(layers[i], 'click', toggle)
};
};
G.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map"></div>
<input id="Didzis_21.03-03.04" rel="d1"/>
<input id="Didzis_04.04-17.04" rel="d2"/>
<input id="Didzis_18.04-01.05" rel="d3"/>
<input id="Didzis_02.05-15.05" rel="d4"/>
</body></html>
Here is my problem: actually I can switch multiple layers on but I can't turn them off. I think that all of the code is good except function toggle(). Also, it would be good if 'rel' attributes wouldn't be necessary, only 'id'.
It looks like each KmlLayer that you create gets orphaned; they are assigned to a function local var named tr, but then never assigned to anything that will remain available across multiple calls to toggle(). I suggest some changes to the toggle() function:
function toggle() {
if (!this.kmlLayer ) {
this.kmlLayer = new G.KmlLayer(
'http://www.eiranet.lv/kartes/Anjo/kmz/' + this.id + '.kmz',
{ preserveViewport:true } );
}
show = !show;
if (show) {
this.kmlLayer.setMap(map)
}
else {
this.kmlLayer.setMap(null)
};
};
After reviewing your page in some more detail, I suggest additional changes:
function toggle() {
if (!this.kmlLayer ) {
this.kmlLayer = new G.KmlLayer(
'http://www.eiranet.lv/kartes/Anjo/kmz/' + this.id + '.kmz',
{ preserveViewport:true } );
this.displayIsOn = false;
}
//show = !show; -- Remove this line, it is causing display state problems
if ( this.displayIsOn ) {
this.kmlLayer.setMap( null );
this.displayIsOn = false;
}
else {
this.kmlLayer.setMap( map );
this.displayIsOn = true;
};
};

How do I display the location of the user on a Google Map in HTML5?

I'm trying to put a Google map in my page and make it so that when the page loads the map will display exactly the location of the user. In order to do so, I've taken the google maps API code and inserted it into my HTML5 page. At first the browser did ask for permission to share my location but it isn't actually showing this location on the map; I've tried with two or more combinations of functions but it is still not working.... please, I need help! If anyone can tell me what is wrong with the code please do:
<html lang="en" manifest="halma.manifest">
<head>
<meta charset="utf-8">
<title>helmas</title>
<link rel="stylesheet" type="text/css" href="css2.css">
<script src="jquery-1.4.2.min.js" type="text/javascript"></script>
<script src="http://maps.google.com/maps?file=api&v=2&sensor=false&key=ABQIAAAAycdS3aS7dItIegOaJzT2RBT2yXp_ZAY8_ufC3CFXhHIE1NvwkxSiGkO1l1KdZvNzo-8b-o7M21o4UA"></script>
<!--[if IE]>
<script src="excanvas.js"></script>
<![endif]-->
</head>
<<body onload="loadMap()" onunload="GUnload()">
<article>
<div id="map" style="width:100%;height:800px;"></div>
<script>
if (navigator.geolocation) {
// try to get the users location
}
if (navigator.geolocation) {
var timeoutVal = 10 * 1000 * 1000;
navigator.geolocation.watchPosition(showPositionOnMap, errorMessage,
{ enableHighAccuracy: true, timeout: timeoutVal, maximumAge: 0 });
}
else {
alert("Geolocation is not supported by this browser");
}
var map = null;
function loadMap() {
map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(52.2021, 0.1346 ), 12); // (sets the map centre to Cambridge UK)
map.setUIToDefault();
}
function showPositionOnMap(position) {
var geoCoords = new GLatLng(position.coords.latitude, position.coords.longitude);
map.addOverlay(new GMarker(geoCoords));
}
function errorMessage(error) {
var errors = {
1: 'Permission denied',
2: 'Position unavailable',
3: 'Request timeout'
};
alert("Error: " + errors[error.code]);
}
</script>
Perhaps the sensor parameter in the maps invocation needs to be set to "true" - at the moment you have it set to "false". So your script tag should contain this url
<script src="http://maps.google.com/maps?file=api&v=2&sensor=true&key=ABQIAAAAycdS3aS7dItIegOaJzT2RBT2yXp_ZAY8_ufC3CFXhHIE1NvwkxSiGkO1l1KdZvNzo-8b-o7M21o4UA"></script>
For more info:
Google Maps Api sensor location

Google maps API : V2 : Custom infowindow with bindInfoWindowHtml

The API documentation gave me hopes last night with "bindInfoWindowHtml".
But it doesn't seem to replace the default infoWindow, even when you provide your own class etc.
I have tried using other ideas like the labeledmarker. But it doesn't support draggable markers. Hence can't use it in my application.
Here is the sample code which shows the info. window inside, the original bubble.
Isn't there a way to override that window as well !
`
<style type="text/css">
.infoWindowCustomClass
{
width: 500px;
height: 500px;
background-color: #CAEE96;
color: #666;
}
</style>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example</title>
<script src="http://maps.google.com/maps?file=api&v=2&sensor=false&key="" type="text/javascript"></script>
<script type="text/javascript">
function load() {
if (GBrowserIsCompatible())
{
// Create our "tiny" marker icon
var blueIcon = new GIcon(G_DEFAULT_ICON);
blueIcon.image = "http://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png";
// Set up our GMarkerOptions object
markerOptions = { icon:blueIcon };
var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(33.968064,-83.377047), 13);
markerOptions.title = "fart";
var point = new GLatLng(33.968064,-83.377047);
var marker = new GMarker(point);
var tempName = document.getElementById("infoWindowCustom");
marker.bindInfoWindowHtml(tempName);
map.addOverlay(marker);
}
}
</script>`
And here is the DIV -
<DIV id="infoWindowCustom" name="infoWindowCustom" class="infoWindowCustomClass">
Name : <TEXTAREA NAME="nameID" ID="nameID" ROWS="2" COLS="25"></TEXTAREA>
Comments : <TEXTAREA NAME="commentsID" ID="commentsID" ROWS="4" COLS="25"></TEXTAREA>
</DIV>
Solved it as below -
Instead of binding it as above, I take the lang/lats and launch a div at that place.
That seems to work just fine.