How can I learn pixels band values from image in screen of Earth Engine? - google-earth-engine

I want to learn pixels band values, for example when I clik on mNDWI image in screen of Earth Engine, I need learning values of red, green and blue
var geometry=ee.Geometry.Polygon([[38.877002459052335,40.75574968156597],
[41.206104021552335,41.17882292442983],
[40.645801287177335,41.59918091806734],
[40.052539568427335,41.84517989453356],
[39.569141130927335,41.886088143011904],
[38.800098162177335,41.48405920501165],
[38.877002459052335,40.75574968156597],
]);
var s2SR = ee.ImageCollection('COPERNICUS/S2_SR')
//filter start and end date
.filter(ee.Filter.calendarRange(2020,2020,'year'))
.filter(ee.Filter.calendarRange(8,8,'month'))
//filter according to drawn boundary
.filterBounds(geometry)
.filterMetadata('CLOUD_COVERAGE_ASSESSMENT', 'less_than',10);
//Map.addLayer(s2SR, {bands:['B4', 'B3', 'B2'], min:0, max:8000}, 's2SR');
// adding mNDWI function
var addMNDWI = function(image) {
var mndwi = ee.Image(image).normalizedDifference(['B3', 'B11']).rename('MNDWI');
return ee.Image(image).addBands(mndwi);
};
var mndwı=s2SR
.map(addMNDWI);
Map.addLayer(mndwı.first(), { min:245, max:5000}, 'mndwı');

It is simple to view the values for any displayed image. First, click on the “Inspector” tab in the top right pane of the Earth Engine Code Editor.
Then, click wherever you want on the map. The Inspector tab will display:
The coordinates of the location you clicked.
The values of every band of every image under that point. (When there are many, as a chart.)
The details of the image (or feature), including properties.

Related

icons must be visible at different view level

I use openlayers3 to build an application
I would like to change the zoomlevel icons are visible at
https://bestofosm.org/?lon=4.0798&lat=50.9136&zoom=15#interesting-het-loo-garden
for example
if you go to London you see airports are visible at zoomlevel 10
lets say I want all touristic icons visible at zoomlevel 10
and airport icons at zoomlevel 15
is this possible?
The most simple solution is to put your markers in different layers and give each layer a minResolution and maxResolution. When the map zooms outside these resolutions the layers will automatically become hidden. Something like:
var touristicIcons = new ol.layer.Vector({
source: touristicIconsSource,
minResolution: xx
maxResolution: xx
});
// Repeat for airports layer, with different resolutions
Writing down a zoom level as a resolution will not work. You will need to find out what resolution belongs to your desired zoom level. The easiest way to do this is with this little hack, that logs the zoom level and resolution every time you scroll through the map:
map.getView().on('change:resolution', function (event) {
var view = event.currentTarget;
console.log('Zoom: ' + view.getZoom() +
', resolution: ' + view.getResolution());
});

Place objects on a defined shape

I'm looking for a way, to allow a drag and drop, only on what's the area of an image.
So, if the image is the following:
I will have the option to add another layer on top, with some text, but that new layer, can't go anywhere, but inside the shape of that image.
So, after some research, I still wonder how can I achieve something like that?
I know I can use map and area to map existing elements on an image, but how can I add new elements, that fit only to that map? Any ideas?
To illustration your solution, let's assume you want to drop a raindrop in your cloud and be sure all raindrop pixels are fully inside the cloud...
Then the answer to your question requires asking this question:
Are all opaque raindrop pixels fully inside the cloud?
To answer this question, you must compare every pixel on the raindrop with every pixel underneath.
If the raindrop pixel is transparent, then ignore this pixel because this part of the raindrop is transparent anyway.
If the raindrop pixel is opaque and the pixel underneath is transparent, then this raindrop pixel is not contained in the cloud.
If both the raindrop pixel & underneath pixel are opaque, then this raindrop pixel is contained in the cloud.
You can get the required transparency information about the raindrop and cloud by drawing their images on a canvas and then requesting getImageData. 'getImageData' returns the red, green, blue & alpha information about every pixel on the canvas. To answer the question, we just need the alpha information.
Here's annotated code and a Demo:
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var offsetX,offsetY;
// load the cloud and raindrop images
var cloudmap,rainmap;
var rain=new Image();
rain.crossOrigin='anonymous';
rain.onload=start;
rain.src='https://dl.dropboxusercontent.com/u/139992952/raindrop1.png';
var cloud=new Image();
cloud.crossOrigin='anonymous';
cloud.onload=start;
cloud.src="https://dl.dropboxusercontent.com/u/139992952/cloud.png";
var cloud1=new Image();
cloud1.crossOrigin='anonymous';
cloud1.onload=start;
cloud1.src="https://dl.dropboxusercontent.com/u/139992952/multple/cloud1.png";
var imageCount=3;
function start(){
if(--imageCount>0){return;}
// resize the canvas to the size of the cloud
// and draw the cloud on the canvas
cw=canvas.width=cloud.width;
ch=canvas.height=cloud.height;
draw();
// create a transparency map of the cloud
cloudmap={
width:cloud.width,
height:cloud.height,
map:transparencyMap(cloud),
};
// create a transparency map of the raindrop
rainmap={
width:rain.width,
height:rain.height,
map:transparencyMap(rain),
}
// listen for mousemove events
$("#canvas").mousemove(function(e){handleMouseMove(e);});
// listen for window scroll events
calcCanvasOffset();
$(window).scroll(function(){ calcCanvasOffset(); });
}
function transparencyMap(img){
// create a temp canvas sized to the img size
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
c.width=img.width;
c.height=img.height;
// draw the img on the canvas
cctx.drawImage(img,0,0);
// get the pixel data for every pixel on the canvas
var data=cctx.getImageData(0,0,c.width,c.height).data;
// create an array that reports the status
// of every pixel on the canvas
// (status: true if opaque, false if transparent)
var map=[];
for(var i=0;i<data.length;i+=4){
map.push(data[i+3]>250);
}
return(map);
}
function draw(mouseX,mouseY,isContained){
// draw the cloud
ctx.clearRect(0,0,cw,ch);
if(isContained){
// draw the blue cloud indicating the raindrop is not fully contained
ctx.drawImage(cloud,0,0);
}else{
// draw the yellow cloud indicating the raindrop is fully contained
ctx.drawImage(cloud1,0,0);
}
// if the mouse position was supplied
if(mouseX){
ctx.drawImage(rain,mouseX-rain.width/2,mouseY-rain.height/2);
}
}
function AcontainsB(ax,ay,amap,bx,by,bmap){
// set a flag indicating of the raindrop is fully contained in the cloud
var isContained=true;
// calc the relative position of the raindrop vs cloud in the canvas
var deltaX=bx-ax;
var deltaY=by-ay;
// test every pixel of B against A
// if B is opaque and a is not opaque then B is not contained by A
var y=0;
while(isContained && y<bmap.height){
var x=0;
while(isContained && x<bmap.width){
// calc the map array indexes for the cloud(A) & raindrop(B)
var mapIndexA=(y+deltaY)*amap.width+(x+deltaX);
var mapIndexB=y*bmap.width+x;
// if the raindrop is opaque at this pixel
if(bmap.map[mapIndexB]){
// ...and if this pixel is off canvas
if(mapIndexA<0 || mapIndexA>=amap.map.length){
// ...then the raindrop is not in the cloud at this pixel
isContained=false;
// ...or if the pixel under the raindrop is transparent
}else if(!amap.map[mapIndexA]){
// ...then the raindrop is not in the cloud at this pixel
isContained=false;
}
}
x++;
}
y++;
}
return(isContained);
}
function handleMouseMove(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// calc the top-left corner of the raindrop image
var rainX=parseInt(mouseX-rain.width/2);
var rainY=parseInt(mouseY-rain.height/2);
// ask if the raindrop is fully contained in the cloud
var isContained=AcontainsB(0,0,cloudmap,rainX,rainY,rainmap);
// redraw the cloud & raindrop
draw(mouseX,mouseY,isContained);
}
// recalc the canvas offsetX & offsetY
function calcCanvasOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Use the mouse to drag the raindrop over the canvas<br>The cloud turns blue if the rain is fully inside the cloud</h4>
<canvas id="canvas" width=600 height=500></canvas>
You can use this "transparency mapping" to test anything you can draw into a canvas including images and text. Note that text is drawn with context.fillText.
If you're dropping a text element external to the canvas (maybe using jqueryUI or native "draggable"), you will have to:
Fetch the x,y position of the drop.
Fetch the text content of the dropped element.
Create a temporary canvas containing the text. Do it like this...
function textToCanvas(text,fontsize,fontface){
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
cctx.font=fontsize+'px '+fontface;
var textWidth=cctx.measureText(text).width;
c.width=textWidth;
c.height=fontsize+4;
cctx.font=fontsize+'px '+fontface;
cctx.textBaseline='top';
cctx.fillText(text,0,0);
return(c);
}
Use the temporary canvas just like an image to create a transparency map. This is possible because the canvas will accept another canvas as its image source.
Good luck with your project.
[ Additional questions from comments ]
Additional Question:
"How will this react when you have a raindrop placed somewhere in the
cloud (saved it's position), and then you try to add something that's
on top of it?" Said another way: "How can I test if 2 objects are
overlapping?"
Answer: You can test if 2 objects overlap by using transparency maps again. Create another test (AintersectsB) which tests if any pixel in A is opaque while the associated pixel in B is also opaque. You can start with the AcontainsB and modify it to create the AintersectsB test.
Additional Question:
"How can I save and later restore dropped object positions?"
Answer: Since canvas doesn't remember what it draws, you must remember for it. This is usually done by creating a javascript object for each dropped item and saving all these objects in an array. That way if you need to save the positions on a server you can use JSON.stringify to turn the array of objects into a string and send that string to the server to be saved in a database (or file). To recreate your work, the server pulls the string from the database and sends it to the browser. The browser uses JSON.parse to turn the string back into an array of javascript objects. Then you can redraw the scene exactly as it was using the information in the objects.

Flex scrolling more than 10.000 pixels

The Flex Canvas container is limited to 10,000x10,000 pixels. Yet, I've seen Flex apps that are scrolling way more than 10,000 pixels. Any idea how this can be done?
The content I want to scroll is in pieces already, but I need to add those pieces to something that can scroll vertically more than 10,000 pixels.
Depending on what you actually want to display you may be able to split your content into tiles. This is how Google Maps works, every time the map is moved the program determines which tiles are visible on the screen and loads them in. Any markers or overlays that are on the map are notified that the map has moved and determine where their new location is. If their location is off the screen they can be removed from the canvas. For example, the width of all the tiles at zoom level 20 on Google Maps is (256 pixels * 2^20) which equals 268,435,456 total pixels.
Essentially you just need to create a special Sprite that keeps track of the actual x,y location it is supposed to be positioned at. Any time the container moves you simply iterate through all of the child objects and determine where to put them.
function onCanvasScroll() {
//determine the top left coordinates of the canvas
//you will figure out how to do this depending on how the scrolling window
//is implemented
var canvas_scroll_x;
var canvas_scroll_y;
//create a bounding box for the canvas
var view_bounds = new Rectangle(canvas_scroll_x, canvas_scroll_y, canvas.width, canvas.height);
for (child in canvas) {
var x = child.actual_x - view_bounds.x;
var y = child.actual_y - view_bounds.y;
var childBounds = new Rectangle(x, y, child.width, child.height);
//determine if the component is visible on screen
if (view_bounds.intersects(child_bounds)) {
child.visible = true;
child.x = x;
child.y = y;
}
else {
child.visible = false;
}
}
}
So if you have a canvas that is positioned at (100, 20000), a sprite that is positioned at (300, 20100), and a window that is (640,408), you would place it at (200, 100) and it would be visible on the screen.
Instead of just setting visible to true or false a better approach would be to remove the items from the canvas entirely when they are not within the bounds of the view.

Resize markers depending on zoom Google maps v3

I have a Google map running on the v3 API, I added some custom markers, is it possible to make them scale depending on the zoom level of the map?
I tried searching the reference but can't seem to find any methods to resize a MarkerImage.
Maybe I have to remove markers everything the map changes zoom and create new markers in a different size?
This code will resize every time the map is zoomed so it always covers the same geographic area.
//create a marker image with the path to your graphic and the size of your graphic
var markerImage = new google.maps.MarkerImage(
'myIcon.png',
new google.maps.Size(8,8), //size
null, //origin
null, //anchor
new google.maps.Size(8,8) //scale
);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(38, -98),
map: map,
icon: markerImage //set the markers icon to the MarkerImage
});
//when the map zoom changes, resize the icon based on the zoom level so the marker covers the same geographic area
google.maps.event.addListener(map, 'zoom_changed', function() {
var pixelSizeAtZoom0 = 8; //the size of the icon at zoom level 0
var maxPixelSize = 350; //restricts the maximum size of the icon, otherwise the browser will choke at higher zoom levels trying to scale an image to millions of pixels
var zoom = map.getZoom();
var relativePixelSize = Math.round(pixelSizeAtZoom0*Math.pow(2,zoom)); // use 2 to the power of current zoom to calculate relative pixel size. Base of exponent is 2 because relative size should double every time you zoom in
if(relativePixelSize > maxPixelSize) //restrict the maximum size of the icon
relativePixelSize = maxPixelSize;
//change the size of the icon
marker.setIcon(
new google.maps.MarkerImage(
marker.getIcon().url, //marker's same icon graphic
null,//size
null,//origin
null, //anchor
new google.maps.Size(relativePixelSize, relativePixelSize) //changes the scale
)
);
});
Unfortunately, you would have to setIcon every single time. However, you can pre-define them, and then just apply them to the marker.
zoomIcons = [null, icon1, icon2]; // No such thing as zoom level 0. A global variable or define within object.
marker.setIcon(zoomIcons[map.getZoom()]);
To add to the map an image that follows the zoom level, use a GroundOverlay.
https://developers.google.com/maps/documentation/javascript/groundoverlays

Creating drag bar purely in actionscript

I've been having trouble creating a mechanism to allow the user to select a span of time from a timeline. Basically i want them to be able to click and drag horizontally, and retrieve the start and end positions of that event.
I especially need to include the case where the event goes off the edge of the screen (even if the end position is snapped to the edge of the screen that's fine).
While doing all of this, I want to be able to draw a box that goes from the start of the event to the current position of the mouse, so that it's obvious which area if being selected.
Basically, it doesn't seem to me that you're dragging something. You just have a sequence of press, move and release. You will have to click on something, I bet you could consider the press event on the timeline itself. So it'll be something like:
timeline.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
timeline.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
// the next line just considers that leaving the object surface is the same as depressing the mouse button
timeline.addEventListener(MouseEvent.MOUSE_OUT, onMouseUp);
function onMouseDown(evt:MouseEvent):void {
// add the event listener for the mouse move action
timeline.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
// create the movie clip for the box
// you get the mouse coordinates from evt.localX and evt.localY (relative to the origin of the timeline movieclip) or evt.stageX and evt.stageY (as global values)
}
function onMouseMove(evt:MouseEvent):void {
// adjust the selection width and height
// you get the mouse coordinates from evt.localX and evt.localY (relative to the origin of the timeline movieclip) or evt.stageX and evt.stageY (as global values)
}
function onMouseUp(evt:MouseEvent):void {
// remove the event listener for the mouse move, that means that the function onMouseMove will no longer be called
timeline.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
// brush up and send the final coordinates of the selection to the next function
}
For the selection graphics itself, you can either use an instance of a movie clip from your library, or you could simply create an empty movie clip, make it semitransparent and draw a rectangle in it, like so:
var selection:MovieClip = new MovieClip();
selection.alpha = 0.5;
selection.graphics.beginFill(0x000000);
selection.graphics.drawRect(x,y,width,height);
selection.graphics.endFill();
this.addChild(selection);

Resources