ESRI JS API - Buffer FeatureLayer - javascript

I have a Feature Layer that I would like to buffer using user input and a geometry service.
FeatureLayer:
var texasPipeline = new FeatureLayer(pipeURL, {
mode: FeatureLayer.MODE_ONDEMAND,
outFields: ["*"],
definitionExpression:texasPipeQuery
});
BufferParameters:
var params = new BufferParameters();
params.distances = [distance];
params.unit = units;
params.outSpatialReference = map.spatialReference;
params.geometries = texasPipeline;
map.graphics.clear();
geomSvc.buffer(params, showBuffer);
The server is returning an error saying that geometries must be supplied. My guess here is that i need to pass in the geometry of the FeatureLayer as opposed to the FeatureLayer itself. How do i get at the geometries of the FeatureLayer and appropriately pass that into the BufferParameters??
EDIT:
Additionally I have tried to loop through as you can see in the code bellow. passing the array of geometries into the BufferParameters still does not return successfully.
var texasPipelineGeom = [];
var graphics = texasPipeline.graphics;
for (var G in graphics) {
var g = graphics[G]["geometry"];
console.log(g);
texasPipelineGeom.push(g);
}

What is the error you re receiving with the edits you made, that looks to be a good start. The buffer parameters does take an array of geometries instead of a feature layer.
You could use something like this (untested, just take as pseudo code):
params.geometries = texasPipeline.graphics.map(function (graphic) {
return graphic.geometry;
});
If using polygons, sometimes the geometry service will complain about the polygons not being simplified. You can find a full working example with polygons here: https://developers.arcgis.com/javascript/3/jssamples/util_buffergraphic.html, You will just need to correctly get your geometries out of the feature layer and add them to params.geometries.
var buffer = function buffer (point, radius) {
var promise = new Deferred();
var gsvc = new GeometryService(CONFIG.GEOMETRY_SERVICE_URL);
var params = new BufferParameters();
params.geometries = [point];
params.distances = [radius];
params.unit = GeometryService.UNIT_KILOMETER;
params.outSpatialReference = new SpatialReference(54010);
gsvc.buffer(params, promise.resolve, console.error);
return promise;
};

What vesrion of js api you are using? Starting from version 3.13 there is a module esri/geometry/geometryEngine. With this module you can do geometry operation on the client side without geometry service. Here is a good example of using it.
Also take a look at module esri/graphicsUtils to get geometries from graphics.

Related

how to move heavy geocoding to a web-worker?

I have very big list of geo points which I want to translate to coordinates with the geocoder and the best way I think is to move the task to a web worker, otherwise the Firefox times out and never loads the page.
// the main html file:
var myWorker = new Worker('datapointscollection.js');
myWorker.onmessage = function(e) {
document.getElementById('loadingStatus').innerHTML = count + " elements from " + all + "are ready.";
if (count == all) {
myWorker.terminate();
myWorker = undefined;
}
};
myWorker.postMessage([geocodingParams]);
// the worker js file:
self.importScripts("http://js.api.here.com/v3/3.0/mapsjs-core.js");
self.importScripts("http://js.api.here.com/v3/3.0/mapsjs-service.js");
self.importScripts("http://js.api.here.com/v3/3.0/mapsjs-ui.js");
self.importScripts("http://js.api.here.com/v3/3.0/mapsjs-mapevents.js");
self.addEventListener(
'message',
function(e) {
var count = 0;
var all = 0;
// Initialize the platform object:
var platform = new H.service.Platform({
'app_id': 'myappID',
'app_code': 'myappCODE'
});
var geocoder = platform.getGeocodingService();
var onResult = function(result) {};
var findLocations = function(geocodingParams) {
var i=0;
all = geocodingParams.length;
for (i=0; i<geocodingParams.length; i++) {
geocoder.geocode(
geocodingParams[i],
onResult,
function(e){
alert(e);
} );
count = i;
self.postMessage(count, all);
}
};
findLocations(e.data[0]);
},
false);
I tried different approaches, but executing the worker script fails with different errors. The last problem is ReferenceError: document is not defined in mapsjs-core.js:158:623. and after a while another error:
NetworkError: A network error occurred. from datapointscollection.js:1
For huge number of geocodes, you should consider batch geocoding.
Check developer’s guide at developer.here.com
It looks like the files you are importing into your worker depend on a DOM existing. Your web worker doesn't have a DOM, so you will have to use dependencies that don't need a DOM (if it will work in node, it will work without a DOM). Check the documentation for your dependencies to see if there a version that works in node or doesn't need a DOM, and use that version in your web worker. (It might be just the mapsjs-service.js file. see if you can get away with just that).
See also Web Workers API

three.js Apply image on existing object

I try to add an img on one object to change his aspect. But all my test result by white object...
The purpose is juste to apply an image on object (all face). He my test code :
var obj = scene.getObjectByName('wall_20_118')
var texture = new THREE.ImageLoader().load( 'core/img/3d/shutter.jpg' );
material = new THREE.MeshBasicMaterial({map: texture,side:THREE.DoubleSide });
obj.material = material
obj.material.map.needsUpdate = true
The object turn to white but I can see my image.
How can I do that ?
Thank in advance
You should be using the THREE.TextureLoader and it's asynchronous, which means that the image is loaded and a callback function will be invoked once the loading finished and the image can be used as a texture on the object.
You would have to change your code like this:
var obj = scene.getObjectByName('wall_20_118');
new THREE.TextureLoader().load( 'core/img/3d/shutter.jpg', function onLoad(texture) {
var material = new THREE.MeshBasicMaterial({
map: texture,
side: THREE.DoubleSide
});
obj.material = material
} );

projectionStream is not a function in D3.js v4

We are working on this website http://bandaultralarga.italia.it/mappa-bul/
On that page we have a gMap where we draw some polygons on top, using d3(v3) and topoJson.
Now we want (would like) to switch to the new v4 to add new data viz design on the page but keeping what we already had.
Troubles come in the overlay function below where we translate the coordinates into the Google Map system.
Referring to D3 v4 API Docs we switched from:
path = d3.geo.path().projection(googleMapProjection);
to:
path = d3.geoPath().projection(googleMapProjection);
but this generates the subject error (projectionStream is not a function.)
Any clue to get this to work again?
var overlay = new google.maps.OverlayView();
overlay.onAdd = function () {
var div = document.createElement('div');
div.id = 'svg_map';
div.style.borderStyle = 'none';
div.style.borderWidth = '0px';
div.style.position = 'absolute';
this.getPanes().overlayMouseTarget.appendChild(div);
overlay.draw = function () {
var overlayProjection = this.getProjection();
var googleMapProjection = function (coordinates) {
var googleCoordinates = new google.maps.LatLng(coordinates[0], coordinates[1]);
var pixelCoordinates = overlayProjection.fromLatLngToDivPixel(googleCoordinates);
return [pixelCoordinates.x + 4000, pixelCoordinates.y + 4000];
};
path = d3.geoPath().projection(googleMapProjection); // Here is where troubles come
generaOverlay(overlay, datiShape);
};
};
overlay.setMap(map);
mbostock answer:
Please read the d3-geo release notes or CHANGES.md:
“Fallback projections”—when you pass a function rather than a projection to path.projection—are no longer supported. For geographic projections, use d3.geoProjection or d3.geoProjectionMutator to define a custom projection. For arbitrary geometry transformations, implement the stream interface; see also d3.geoTransform.

Antlr4 Javascript Visitor

I'm currently trying to develope a JavaScript Compiler with the help of an Antlr4 Visitor. I've got this already implemented with Java but cannot figure out how to do this in JavaScript. Probably somebody can answer me a few questions?
1: In Java there is a Visitor.visit function. If im right this isn't possibile with Javascript. Is there a work around for this?
2: My Javascript Visitor got all the generated visiting functions but when I use console.log(ctx) the context is undefined. Any idea why?
Extract from the SimpleVisitor.js:
// Visit a parse tree produced by SimpleParser#parse.
SimpleVisitor.prototype.visitParse = function(ctx) {
console.log(ctx);
};
Main js file:
var antlr4 = require('lib/antlr4/index');
var SimpleLexer = require('antlr4/SimpleLexer');
var SimpleParser = require('antlr4/SimpleParser');
var SimpleVisitor = require('antlr4/SimpleVisitor');
var input = "double hallo = 1;";
var chars = new antlr4.InputStream(input);
var lexer = new SimpleLexer.SimpleLexer(chars);
var tokens = new antlr4.CommonTokenStream(lexer);
var parser = new SimpleParser.SimpleParser(tokens);
var visitor = new SimpleVisitor.SimpleVisitor();
parser.buildParseTrees = true;
var tree = parser.parse();
visitor.visitParse();
This is probably enough to start with ...
Bruno
Edit:
Probably the context is undefined because I call the function without arguments but where do I get the "starting"-context?
Edit2:
So I think I get the idea how this should work out. One Question remaining how do I determine which rule to call next inside each visitor function?
The basic idea behind the visitor is that you have to handle all the logic by yourself. To do this I generated the visitor using antlr. My own visitor overrides all functions that I need to implement my logic.
create lexer, tokens, ...
var antlr4 = require('antlr4/index');
var SimpleJavaLexer = require('generated/GrammarLexer');
var SimpleJavaParser = require('generated/GrammarParser');
var SimpleJavaVisitor = require('generated/GrammarVisitor');
var Visitor = require('./Visitor');
var input = "TestInput";
var chars = new antlr4.InputStream(input);
var lexer = new GrammarLexer.GrammarLexer(chars);
var tokens = new antlr4.CommonTokenStream(lexer);
var parser = new GrammarParser.GrammarParser(tokens);
var visitor = new Visitor.Visitor();
parser.buildParseTrees = true;
var tree = parser.parse();
and call your entry function
visitor.visitTest(tree);
inside your new visitor you need to implement your new logic to determine which function to call next (the right context as argument is important)
var GrammarVisitor = require('generated/GrammarVisitor').GrammarVisitor;
function Visitor () {
SimpleJavaVisitor.call(this);
return this;
};
Visitor.prototype = Object.create(GrammarVisitor.prototype);
Visitor.prototype.constructor = Visitor;
Visitor.prototype.visitTest = function(ctx) {
// implement logic to determine which function to visit
// then call next function and with the right context
this.visitBlock(ctx.block());
};
I hope you can understand my basic idea. If anybody got any questions just comment.

Saving current work from multiple canvas elements

Here is my problem: I have created an image collage function in javascript. (I started off with some code from this post btw: dragging and resizing an image on html5 canvas)
I have 10 canvas elements stacked on top of each other and all parameters, including 2dcontext, image data, positions etc. for each canvas is held in instances of the function 'collage'.
This is working fine, I can manipulate each canvas separately (drag, resize, adding frames, etc). But now and I want the user to be able to save the current work.
So I figure that maybe it would be possible to create a blob, that contains all the object instances, and then save the blob as a file on disk.
This is the function collage (I also push each instance to the array collage.instances, to be able to have numbered indexes)
function collage() {
this.canvas_board = '';
this.canvas = '';
this.ctx = '';
this.canvasOffset = '';
this.offsetX = '';
this.offsetY = '';
this.startX = '';
this.startY = '';
this.imageX = '';
this.imageY = '';
this.mouseX = '';
this.mouseY = '';
this.imageWidth = '';
this.imageHeight = '';
this.imageRight = '';
this.imageBottom = '';
this.imgframe = '';
this.frame = 'noframe';
this.img = '';
collage.instances.push(this);
}
collage.instances = [];
I tried with something like this:
var oMyBlob = new Blob(collage.instances, {type: 'multipart/form-data'});
But that doesn't work (only contains about 300 bits of data).
Anyone who can help? Or maybe suggest an alternative way to save the current collage work. It must of course must be possible to open the blob and repopulate the object instances.
Or maybe I am making this a bit more complicated than it has to be... but I am stuck right now, so I would appreciate any hints.
You can extract each layer's image data to DataURLs and save the result as a json object.
Here's a quick demo: http://codepen.io/gunderson/pen/PqWZwW
The process literally takes each canvas and saves out its data for later import.
The use of jquery here is for convenience:
$(".save-button").click(function() {
var imgData = JSON.stringify({
layers: getLayerData()
});
save(imgData, "myfile.json");
});
function save(filecontents, filename) {
try {
var $a = $("<a>").attr({
href: "data:application/json;," + filecontents,
download: filename
})[0].click();
return filecontents;
} catch (err) {
console.error(err);
return null;
}
}
function getLayerData() {
var imgData = [];
$(".layer").each(function(i, el) {
imgData.push(el.toDataURL("image/png"));
});
return imgData;
}
To restore, you can use a FileReader to read the contents of the JSON back into the browser, then make <img>s for each layer, set img.src to the dataURLs in your JSON and from there you can draw the <img> into onload canvases.
Add a reference (src URL) for the image to the instance, then serialize the instance array as JSON and use f.ex. localStorage.
localStorage.setItem("currentwork", JSON.stringify(collage.instances));
Then to restore you would need to do:
var tmp = localStorage.getItem("currentwork");
collage.instances = tmp ? JSON.parse(tmp) : [];
You then need to iterate through the array and reload the images using proper onload handling. Finally re-render everything.
Can you store image data on client? Yes, but not recommended. This will take a lot of space and if too much you will not be able to save all the data, the user may refuse to allow more storage space etc.
Keeping a link to the image on a server is a better approach for these things IMO. But if you disagree, look into IndexedDB (or WebSQL although deprecated) to have local storage which can be expanded in available space. localStorage can only hold between 2.5 - 5 mb, ie. no image data and only strings. Each char takes two bytes, data-uris adds 33% on top, so this will run empty pretty fast...

Categories

Resources