Save interaction draw openlayers - javascript

Can anybody give me a hint on how can I save the interaction drawings which I draw in openlayers 3? Can I use json for that? Can anybody provide a simple example?
Thanks!

var features = yourLayer.getSource().getFeatures();
var newForm = new ol.format.GeoJSON();
var featColl = newForm.writeFeaturesObject(features);
Then, save it to JSON:
function exportJson(featuresCollection) {
var txtArray = [];
txtArray.push(JSON.stringify(featuresCollection));
// Here I use the saveAs library to export the JSON as *.txt file
var blob = new Blob(txtArray, {type: 'text/json;charset=utf8'});
saveAs(blob, layerName + ".txt")
};
exportJson(featColl);
To load a JSON:
var vectorLayer = new ol.layer.Vector({
source: new ol.source.GeoJSON({
projection: 'EPSG:3857',
url: 'yourFile.json'
})
});

Related

OpenStreetMap OSMXML not rendering

I am trying to offline-render a part of OpenStreetMap, previously loaded as map.osm (OSM XML). I'm starting a localhost and loading the xml from disk.
I tried to use similar example (https://openlayers.org/en/latest/examples/vector-osm.html) changing only the source to my file, yet this didn't work out. Data loaded is pretty much similar to data I see in the example.
I tried a bunch of various approaches, and I still can't render the map. I get no errors, and I can't get what I'm missing.
var vectorSource = new VectorSource({
format: new OSMXML()
});
var xml = await fetch('map.osm').then(res => res.text());
var features = (new OSMXML()).readFeatures(xml);
// Features are parsed OK
vectorSource.addFeatures(features);
var vector = new VectorLayer({
source: vectorSource,
// Using styles, I don't post them here (a lot of code)
style: function (feature) {
for (var key in styles) {
var value = feature.get(key);
if (value !== undefined) {
for (var regexp in styles[key]) {
if (new RegExp(regexp).test(value)) {
return styles[key][regexp];
}
}
}
}
return null;
}
});
map = new Map({
layers: [vector],
target: document.getElementById('map'),
view: new View({
center: [0, 0],
maxZoom: 0,
zoom: 0
})
});

Failing to load CSV data through Omnivore

I am trying to load a CSV file, convert it to GeoJSON, add an empty geoJson layer and then adding data to that geoJson layer. Why is it not working?
var locations = 'locations.csv';
var x = omnivore.csv(locations);
var geojsonLayer = L.geoJson().addTo(map);
geojsonLayer.addData(x);
omnivore.csv returns a layer built with the loaded data, not the underlying GeoJSON object.
Try
var geojsonLayer = omnivore.csv(locations);
geojsonLayer.addTo(map);
Or build your layer and pass it to omnivore.csv:
var geojsonLayer = L.geoJson().addTo(map);
omnivore.csv('locations.csv', null, geojsonLayer);
Or ditch omnivore and use csv2geojson to load your data before populating your layer :
var geojsonLayer = L.geoJson().addTo(map);
xhr = new XMLHttpRequest();
xhr.onload = function() {
csv2geojson.csv2geojson(this.responseText, {}, function(err, data) {
geojsonLayer.addData(data);
});
};
xhr.open('GET', 'locations.csv', true);
xhr.send(null);

How to generate <a> list from published layers in Geoserver?

I am building a webmapping app. I parse the WMS request to have the title of each layer in layers:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8082/geoserver/wms?service=wms&request=GetCapabilities', true);
xhr.onload = function() {
var parser = new ol.format.WMSCapabilities();
var capabilities = parser.read(xhr.responseText);
var layers = capabilities.Capability.Layer.Layer.Title;
};
But then I fail to access to the titles contain in layers:
$.each(layers, function(i)
{
var list = $('</br><a/>')
.text(layers[i])
.appendTo($('div.myDiv'));
});
What did I miss? Thanx for the help.
I think the problem is, that you need the Name of the Layer, not the Title to be able to call it.
So you would parse the capabilities like this:
var layers = capabilities.Capability.Layer.Layer.Name;

Openlayers 3 - Modifying a polygon after draw

I am trying to make a polygon editable after it is drawn with ol.interaction.Draw.When I instantiate ol.interaction.Modify I get a "b.attachEvent is not a function" error. This is the code:
drawPolygon.on("drawend",function(p)
{
setTimeout(function()
{
modifyPoligon = new ol.interaction.Modify({
features: vectorSource.getFeatures()
});
},200);
}
I also use a timeout because in the drawend call the Feature is still not in the layer, is there a better way to get a callback after the feature is drawn and on the layer?
Not sure if suits your case but here's a fiddle with a similar approach: https://jsfiddle.net/ko822xjw/
// Create a draw interaction and add it to the map:
drawInteraction = new ol.interaction.Draw({ source:vectorSource, type:"Polygon" });
map.addInteraction(drawInteraction);
// set listener on "drawend":
drawInteraction.on('drawend', function(e) {
// get drawn feature:
var feature = e.feature;
// remove draw interaction:
map.removeInteraction(drawInteraction);
// Create a select interaction and add it to the map:
selectInteraction = new ol.interaction.Select();
map.addInteraction(selectInteraction);
// select feature:
selectInteraction.getFeatures().push(feature);
// do something after drawing (e.g. saving):
// ...
// Create a modify interaction and add to the map:
modifyInteraction = new ol.interaction.Modify({ features: selectInteraction.getFeatures() });
map.addInteraction(modifyInteraction);
// set listener on "modifyend":
modifyInteraction.on('modifyend', function(evt) {
// get features:
var collection = evt.features;
// There's only one feature, so get the first and only one:
var featureClone = collection.item(0).clone();
// do something after modifying (e.g. saving):
// ...
});
});
It could be as simple as:
var
features = new ol.Collection(),
modify = new ol.interaction.Modify({
features: features
}),
vectorSource = new ol.source.Vector({
features: features
}),
vectorLayer = new ol.layer.Vector({
source: vectorSource
}),
map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'osm'})
}),
vectorLayer
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
}),
drawPolygon = new ol.interaction.Draw({
features: features,
type: 'Polygon'
})
;
map.addInteraction(modify);
map.addInteraction(drawPolygon);
http://jsfiddle.net/jonataswalker/r2g1atty/

Pdf.js and viewer.js. Pass a stream or blob to the viewer

I'm having troubles in finding a solution for this:
I retrieve a PDF blob from a SQL filestream field using Javascript in this way (it's a lightswitch project)
var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
I have the blob and I can even convert it in a filestream or to base64("JVBERi0....." or "%PDF 1.6 ......", etc.)
No problem so far.
Now I need to display it in a viewer. I prefer the viewer to open in a new window but i'm open to embed it into my page somehow.
I'm wondering if I can directly pass the blob or the stream to the viewer and display the document. I've tried something like
PDFView.open(pdfAsArray, 0)
Nothing happens in the embedded viewer in this case.
The pdfAsArray is good since I can display it appending the stream to a canvas within the same page. I just want to display the viewer, not embed the PDF in a canvas, possibly in a new window.
Can anyone provide few lines of code on how to achieve that in Javascript?
I'm using PDFJS.version = '1.0.1040'; PDFJS.build = '997096f';
The code that worked for me to get base64 pdf data loaded was this:
function (base64Data) {
var pdfData = base64ToUint8Array(base64Data);
PDFJS.getDocument(pdfData).then(function (pdf) {
pdf.getPage(1).then(function (page) {
var scale = 1;
var viewport = page.getViewport(scale);
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render({ canvasContext: context, viewport: viewport });
});
});
function base64ToUint8Array(base64) {
var raw = atob(base64);
var uint8Array = new Uint8Array(raw.length);
for (var i = 0; i < raw.length; i++) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
}
This function could be the success function of an api call promise. What I'm doing here is rendering the pdf onto a canvas element myCanvas.
<canvas id="myCanvas"></canvas>
This shows the first page of the pdf but has no functionality. I can see why the viewer is desirable. If I get this hooked up to the viewer (viewer.html / viewer.js) I will edit my answer.
EDIT: How to hook up the viewer
1 In bower.json, add "pdfjs-viewer": "1.0.1040"
2 Html:
<iframe id="pdfViewer" src="lib/pdfjs-viewer/web/viewer.html" style="width: 100%; height: 700px;" allowfullscreen="" webkitallowfullscreen=""></iframe>
3 Change the stupid default document in the viewer.js file:
var DEFAULT_URL = '';
4 Controller:
var pdfjsframe = document.getElementById('pdfViewer');
pdfjsframe.onload = function() {
LoadPdfDocument();
};
$scope.myApiCallThatReturnsBase64PdfData.then(
function(base64Data) {
$scope.base64Data = base64Data;
LoadPdfDocument();
},
function(failure) {
//NotificationService.error(failure.Message);
});
function LoadPdfDocument() {
if ($scope.PdfDocumentLoaded)
return;
if (!$scope.base64Data)
return;
var pdfData = base64ToUint8Array($scope.base64Data);
pdfjsframe.contentWindow.PDFViewerApplication.open(pdfData);
$scope.PdfDocumentLoaded = true;
}
function base64ToUint8Array(base64) {
var raw = atob(base64);
var uint8Array = new Uint8Array(raw.length);
for (var i = 0; i < raw.length; i++) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
If you've got an typed array (e.g. an Uint8Array), then the file can be opened using PDFView.open(typedarray, 0);.
If you've got a Blob or File object, then the data has to be converted to a typed array before you can view it:
var fr = new FileReader();
fr.onload = function() {
var arraybuffer = this.result;
var uint8array = new Uint8Array(arraybuffer);
PDFView.open(uint8array, 0);
};
fr.readAsArrayBuffer(blob);
Another method is to create a URL for the Blob/File object:
var url = URL.createObjectURL(blob);
PDFView.open(url, 0);
If the PDF Viewer is hosted at the same origin as your website that embeds the frame, then you can also view the PDF by passing the blob URL to the viewer:
var url = URL.createObjectURL(blob);
var viewerUrl = 'web/viewer.html?file=' + encodeURIComponent(url);
// TODO: Load the PDF.js viewer in a frame or new tab/window.
I finally made the PDFView.open method working. Now if I embed the viewer into my page and call the open function as Rob suggested in the first 2 examples it works.
For those who are looking for this kind of solution I provide some lines of code here:
This is the code in my Lightswitch mainPage.lsml.js. The js scripts (pdf.js, viewer and Others) are referenced in the main html page of the Lightswitch project (Default.html); I assume it should work with any other html page not Lightswitch based.
myapp.MainPage.ShowPdf_execute = function (screen) {
// Write code here.
// Getting the stream from sql
var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
// Pass the stream to an aspx page that makes some manipulations and returns a response
var formData = new FormData();
formData.tagName = pdfName;
formData.append(pdfName, blob);
var xhr = new XMLHttpRequest();
var url = "../OpenPdf.aspx";
xhr.open('POST', url, false);
xhr.onload = function (e) {
var response = e.target.response;
var pdfAsArray = convertDataURIToBinary("data:application/pdf;base64, " + response);
var pdfDocument;
// Use PDFJS to render a pdfDocument from pdf array
PDFJS.getDocument(pdfAsArray).then(function (pdf) {
pdfDocument = pdf;
var url = URL.createObjectURL(blob);
PDFView.load(pdfDocument, 1.5)
})
};
xhr.send(formData); // multipart/form-data
};
This is the convertDataURIToBinary function
function convertDataURIToBinary(dataURI) {
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var base64 = dataURI.substring(base64Index);
var raw = window.atob(base64);
var rawLength = raw.length;
var array = new Uint8Array(new ArrayBuffer(rawLength));
for (i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}
What is still missed is the possibility to pass the stream directly to the viewer.html page in order to open it in a new window and have a separate ui where make the rendering.
This code is still not working since I got an empty viewer with no document inside:
var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
var url = URL.createObjectURL(blob);
var viewerUrl = 'Scripts/pdfViewer/web/viewer.html?file=' + encodeURIComponent(url);
window.open(viewerUrl);
Looks like the encodeURIComponent(url) is not passing to the viewer a good object to load into the viewer.
Any idea or suggestion?
var url = URL.createObjectURL(blob);
var viewerUrl = 'web/viewer.html?file=' + encodeURIComponent(url);
// TODO: Load the PDF.js viewer in a frame or new tab/window.
//-- Abobe code opens a new window but with errors : 'Missing PDF
// blob://http://server-addr:port/converted-blob'
I am using viewer in an iframe;
<iframe
id="pdfIframe"
src="pdfjs/web/viewer.html"
style="width: 100%; height: 100%;"
>
</iframe>
And fetch API used as follows;
fetch(pdfSourceUrl).then((response: Response) => {
response.blob().then((blob) => {
var url = URL.createObjectURL(blob);
pdfIframe.src = `pdfjs/web/viewer.html?file=${url}`;
});
});
Eventually iframe src created as follows;
http://localhost:9000/pdfjs/web/viewer.html?file=blob:http://localhost:9000/14f6a2ec-ad25-40ab-9db8-560c15e90f6e

Categories

Resources