How can I get the polygon clicked on in ti.map on iOS? - ios

I have a simple map where I draw some polygons. Then I want to capture if the user clicks on a polygon - and get a handle to that polygon (e.g. by a custom id of the polygon or similar).
I use code like this to add the polygon:
var poly = Map.createPolygon({
points : points,
id : 'poly',
fillColor : '#55ec858f',
strokeColor : 'black',
strokeWidth : 2
});
mapView.addPolygon(poly);
where points is an array of latitude/longitude objects. I have registered a click handler:
mapView.addEventListener('click',clickHandler);
... and it is defined like this:
function clickHandler(e){
console.log("click: id=" + e.source.id + ", source=" + JSON.stringify(e.source));
console.log("click: clicksource=" + e.clicksource + ", latitude=" + e.latitude + ", longitude=" + e.longitude);
}
The click handler is triggered once I click within the polygon (well, more correctly it is triggered wherever on the map I click). This is fine. However, on iOS I cannot identify which of the polygons the user clicked on. The output looks like this:
[INFO] : click: id=undefined, source={"horizontalWrap":true,"visible":true,"mapType":1,"rotateEnabled":false,"region":{"longitudeDelta":0.010248234495520592,"latitudeDelta":0.009999999776482582,"longitude":11.154247283935547,"latitude":55.55887985229492}}
[INFO] : click: clicksource=polygon, latitude=55.55712556278878, longitude=11.154479577247997
On Android I get what I want:
[INFO] : click: id=poly, source={"fillColor":"#55ec858f","strokeColor":"black","points":[{"latitude":55.563299,"longitude":11.157998},{"latitude":55.562731,"longitude":11.157987},{"latitude":55.562719,"longitude":11.158029},{"latitude":55.562648,"longitude":11.158027},{"latitude":55.562153,"longitude":11.157851},{"latitude":55.561301,"longitude":11.157834},{"latitude":55.561088,"longitude":11.157913},{"latitude":55.560212,"longitude":11.157896},{"latitude":55.560106,"longitude":11.157935},{"latitude":55.559751,"longitude":11.157928},{"latitude":55.559515,"longitude":11.157882},{"latitude":55.559267,"longitude":11.157731},{"latitude":55.559184,"longitude":11.15775},{"latitude":55.559018,"longitude":11.15783},{"latitude":55.558899,"longitude":11.157953},{"latitude":55.558686,"longitude":11.157928},{"latitude":55.558604,"longitude":11.157864},{"latitude":55.558391,"longitude":11.157859},{"latitude":55.558143,"longitude":11.157834},{"latitude":55.557694,"longitude":11.157804},{"latitude":55.557233,"longitude":11.15769},{"latitude":55.556985,"longitude":11.157623},{"latitude":55.556678,"longitude":11.157513},{"latitude":55.556266,"longitude":11.157317},{"latitude":55.556041,"longitude":11.157291},{"latitude":55.555828,"longitude":11.157245},{"latitude":55.555592,"longitude":11.157157},{"latitude":55.555144,"longitude":11.156961},{"latitude":55.554779,"longitude":11.156786},{"latitude":55.554507,"longitude":11.156677},{"latitude":55.554401,"longitude":11.156675},{"latitude":55.554366,"longitude":11.156632},{"latitude":55.554385,"longitude":11.156451},{"latitude":55.554447,"longitude":11.155964},{"latitude":55.554525,"longitude":11.155484},{"latitude":55.554621,"longitude":11.155014},{"latitude":55.554733,"longitude":11.154556},{"latitude":55.554862,"longitude":11.154111},{"latitude":55.555005,"longitude":11.153681},{"latitude":55.555164,"longitude":11.153268},{"latitude":55.555337,"longitude":11.152873},{"latitude":55.555524,"longitude":11.152498},{"latitude":55.555724,"longitude":11.152145},{"latitude":55.555936,"longitude":11.151815},{"latitude":55.556159,"longitude":11.151509},{"latitude":55.556393,"longitude":11.151228},{"latitude":55.556636,"longitude":11.150974},{"latitude":55.556887,"longitude":11.150747},{"latitude":55.557147,"longitude":11.150549},{"latitude":55.557412,"longitude":11.150379},{"latitude":55.557684,"longitude":11.15024},{"latitude":55.557959,"longitude":11.150131},{"latitude":55.558238,"longitude":11.150053},{"latitude":55.55852,"longitude":11.150006},{"latitude":55.558802,"longitude":11.14999},{"latitude":55.559084,"longitude":11.150006},{"latitude":55.559366,"longitude":11.150053},{"latitude":55.559645,"longitude":11.150131},{"latitude":55.55992,"longitude":11.15024},{"latitude":55.560192,"longitude":11.150379},{"latitude":55.560457,"longitude":11.150549},{"latitude":55.560717,"longitude":11.150747},{"latitude":55.560968,"longitude":11.150974},{"latitude":55.561211,"longitude":11.151228},{"latitude":55.561445,"longitude":11.151509},{"latitude":55.561668,"longitude":11.151815},{"latitude
[INFO] : click: clicksource=polygon, latitude=55.55844486621942, longitude=11.154376566410065
The id is really enough for me to get the relevant data (and be able to show the user some more details about the area).
I have tried to add an event handler to the polygon - but it does not work (and really I would want to use one global event listener as in the example above).
I think the only thing I have not tried yet is to try to calculate which polygon I am inside based on the GPS points... I am not really good at such geometric arithmetic - so would like not to go down that road if possible ;-)
Any good ideas?
Thanks in advance!
Edited:
Forgot to mention platform...
Appc CLI 5.1.0
Studio: 4.4.0
ti.map: 2.3.6 (Android)
ti.map: 2.5.2 (iOS)
/John

You can use e.shape.title
I do it like this:
map.addEventListener('click', function(e) {
Ti.API.info('You clicked ' + JSON.stringify(e.shape.title));
});
I can't remember what is available on the e.shape, but i guess you should be able to find an id, or something else to identify your polygon.

Related

Mapbox GL JS : Popup onclick with external JSON

I am trying to display a popup onclick in Mapbox GL JS when the user clicks a polygon (It's a weather warning box during a Flash Flood Warning).
I have been using this example from Mapbox as a base, and -
This is my JSON file that I am trying to pull data from.
When I click the polygon, there is no popup. When I mouseover it, the cursor changes - so I know the basic possible issues like filename and directory structure are right.
My code below was modified from the example. I am trying to load the "description" of each polygon : (My map is called "topleftmapbox" and the JSON id is "FFWWarning")
// When a click event occurs on a feature in the places layer, open a popup at the
// location of the feature, with description HTML from its properties.
topleftmapbox.on('click', 'FFWWarning', function (e) {
var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].description;
// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(description)
.addTo(topleftmapbox);
});
// The following code below runs correctly and changes the cursor on mouseover.
topleftmapbox.on('mouseenter', 'FFWWarning', function () {
topleftmapbox.getCanvas().style.cursor = 'pointer';
});
// Change it back to a pointer when it leaves.
topleftmapbox.on('mouseleave', 'FFWWarning', function () {
topleftmapbox.getCanvas().style.cursor = '';
});
I have a feeling that my issue is somewhere in this part of the code :
var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].description;
I am still new with Mapbox and I have tried looking through here and various sources online to fix this. I am hoping the issue is just that I have the description variable set wrong and that I am missing something simple.
I debugged the code that you provided and found that variable coordinates was containing an object having array of lat-lng.
Modifying that part should fix the issue.
var coordinates = e.features[0].geometry.coordinates[0][0].slice();
In coordinates[0][0], second index determines the position of popup.
Here is the working code. https://jsbin.com/suzapug/1/edit?html,output

Update Mapbox direction instructions while driving/walking + add direction indicator

I'm building a web app to view featured walking routes in my neighbourhood.
User opens the app and sees all different routes.
App gets current location and checks for most nearby route.
App requests the route to one of my featured routes.
User can use the app to navigate to a marker from my featured route that is most nearby.
I'm working with the Directions Service which can give me a list of walking instructions like this:
I'm now trying to combine the directions with my current location. What is the best option to do this? I want to update the instructions based on my current location so for example if I head east on the Amstelkade I want to see the next instruction at the top. I came up with the following:
Add GeolocateControl to Mapbox
let geolocate = new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
})
map.addControl(geolocate);
Put a listener on the geolocate change event and update starting place (origin) to get the latest direction instructions.
geolocate.on('geolocate', function(location) {
currentLocation = location;
setOrigin(location);
setDestination(location);
});
function setOrigin(location){
if(Object.keys(directions.getOrigin()).length === 0){
directions.setOrigin([location.coords.longitude, location.coords.latitude]);
}
}
I'm a little bit lost if this is a proper solution because in this way i'm making a lot of requests (could put a debouncer on the geolocate event though). Is there a better way to solve this and make it more user friendly?
Question 2: is it possible to add a direction indicator (blue beam of direction you're heading) to Mapbox like Google does?
Thanks all!

Getting Ink Strokes in MyScript

I'm working with MyScript, and I noticed that for the web API (find examples here: http://doc.myscript.com/MyScriptCloud/3.1.0/myscript-cloud/examples.html), a "stroke" type is required, as well as all of the coordinates describing the stroke.
I'm wondering what software I should use to generate these strokes, or how I could program it myself? There's nothing in the official documentation.
Thanks for your time.
The stroke type expected by the server is a json object with x, y attributes, containing both arrays of integer. These values represent x,y coordinates user input while writing on the device touchscreen. You can collect and add timestamp as an optional ‘t’ attribut of the JSON stroke type structure.
As a first option, you can use our webcomponents : myscript-math-web, myscript-text-web or even MyScriptJS to manage the user ink capture and the rendering in a canvas.
You can also grab the user handwriting by yourself, in this case we recommend you to use (jquery PEP)[https://github.com/jquery/PEP] (Pointer Event Polyfill) that will help you to manage user touchscreen events, namely pointer events.
You will have to listen for pointerdown, pointermove and pointerup events. Once such event occurs, add the event coordinates to your structure this way, for instance:
var myStroke;
document.querySelector('#myCanvasId').addEventListener('pointerdown', function (e) {
e.preventDefault();
mystroke = {x : [], y : [], t : []};
mystroke.x.push(e.clientX);
mystroke.y.push(e.clientY);
mystroke.t.push(e.timestamp)
}, false);
document.querySelector('#myCanvasId').addEventListener('pointermove', function (e) {
e.preventDefault();
mystroke.x.push(e.clientX);
mystroke.y.push(e.clientY);
mystroke.t.push(e.timestamp)
}, false);
document.querySelector('#myCanvasId').addEventListener('pointerup', function (e) {
e.preventDefault();
mystroke.x.push(e.clientX);
mystroke.y.push(e.clientY);
mystroke.t.push(e.timestamp)
// Send your stroke to the server
mystroke = {};
}, false);
If you need more detailed explanation, you can have a look at this video. Details about digital ink capture at 10:40.

Openlayers 3.6: Getting the center of the current map view

I'm trying to get the current center of an Openlayers map in lat/lon coordinates. I've got the following event handler setup:
this.map.on('pointermove', function (e) {
if (e.dragging) {
console.log(that.map.getView().getCenter());
}
});
This works, but I'm getting weird values. Here's an example:
[9318218.659044644, 3274618.6225819485]
Those are obviously not lat/lon values :) Do I need to transform this somehow? Thanks!
I'm not super familiar with openlayers but it sounds like the map is in different projection.
Check out the following on spherical_mercator, transform,
Open Layers projections
UPDATED
I've done a little more research, check out this example. Not sure what the projection your view is in. the map in this example is in ''EPSG:21781' if you go to a js console and enter map.getView().getCenter() you get [693230.7161150641, 179010.3389264635] but if you enter ol.proj.transform(map.getView().getCenter(), 'EPSG:21781', 'EPSG:4326') you get [8.658936030357363, 46.75575224283748] hope that helps.
For those who are working with angular.
Also, I would consider searching the projection of the map, instead of entering it manually.
import * as olProj from 'ol/proj'
import Map from 'ol/Map'
// ...
olProj.transform(
this.map.getView().getCenter(),
this.map.getView().getProjection(),
'EPSG:4326',
)
Update for OpenLayers 6 (assuming your map is called 'map') the following gives an array of [lon, lat] for the centre of your map's view.
ol.proj.toLonLat( map.getView().getCenter() )

How to get absolute coordinates in Safari on iOS?

I need to automate tapping on a specific bar in a bar chart that's stored inside of a canvas in a Safari browser on iOS. There's no useful information in the html to get this information unfortunately so I need to rely on hard coded coordinates in order to tap where I need to. On Android I can easily do this by turning on Pointer location in the developer settings - I can't seem to find the equivalent on iOS.
I found some javascript code snippets on the net that I could inject into the web inspector on safari to give me coordinates based on user touch but it seems like the coordinates I get there are relative to the web screen, I need absolute coordinates of the entire screen (if resolution is 1920x1080 I need to select which pixel to tap on).
$( document ).click(
function( event ){
// Client variables.
console.log(
"clientX/Y: " +
event.clientX + ", " +
event.clientY
);
// Page variables. NOTE: These are the ones
// that are officially supported by the
// jQuery Event object.
console.log(
"pageX/Y: " +
event.pageX + ", " +
event.pageY
);
// Hrule.
console.log( "......" );
}
);
I didn't find a way to do this using code but I found out that you can easily get this information from taking a picture on your phone and then opening the file up in an image editing program. In my case I used Seashore.

Resources