Taking Screenshot Ionic framework - javascript

I'm building Ionic application that have geolocation (Google Api), but that's irelevant, in upper right corner is button which i want to make to take screenshot and automatically make popover with options to send that screenshot image via email, viber..., but i don't have an idea how to take that screenshot, I googled and googled without any luck, please help.
app.controller('MapCtrl', function($scope, $cordovaGeolocation, $ionicLoading, $ionicPlatform) {
$ionicPlatform.ready(function() {
$ionicLoading.show({
template: '<ion-spinner icon="bubbles"></ion-spinner><br/>Acquiring location!'
});
var posOptions = {
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 0
};
$cordovaGeolocation.getCurrentPosition(posOptions).then(function (position) {
var lat = position.coords.latitude;
var long = position.coords.longitude;
var myLatlng = new google.maps.LatLng(lat, long);
var mapOptions = {
center: myLatlng,
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
$scope.map = map;
$ionicLoading.hide();
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'Lokacija'
});
}, function(err) {
$ionicLoading.hide();
console.log(err);
});
});
});

Two options, as far as I can tell:
Use a third-party Cordova plugin, such as https://github.com/gitawego/cordova-screenshot - this will most likely include the application's UI elements too, though, which might not be what you want.
Perhaps a better idea would be to use the Google Static Maps API - you can pass the current parameters from your dynamic map to it, and it'll return an image version.

This should get you started: How to take a screen shot in ionic
After you received the picture from the plugin, you can just use ionic's popover service to display it there.

This below code should help
*The function will take screenshot and share popup
For More details you can visit SocialSharing and Screenshot Ionic offical page
import { SocialSharing } from '#ionic-native/social-sharing/ngx';
import { Screenshot } from '#ionic-native/screenshot/ngx';
constructor(
private socialSharing: SocialSharing,
private screenshot: Screenshot
) { }
share(){
this.platform.ready().then(() => {
this.screenshot.URI(80)
.then((res) => {
//this.socialSharing.share('df',res.URI,null)
this.socialSharing.share('',null,res.URI,null)
.then(() => {},
() => {
alert('SocialSharing failed');
});
},
() => {
alert('Screenshot failed');
});
});
}

Related

Remove option from Google Maps embedded

frameborder="0" style="border:0" src="https://www.google.com/maps/embed/v1/directions?origin=rishra&destination=kolkata&key=MY-API-KEY&zoom=12" allowfullscreen>
Results>
enter image description here
Want to remove that box which shows location of two points and more options
You are using a Directions mode of Maps Embed API and it seems that the origin and destination information is part of the API and can't be removed. If you would only like to show the directions of your origin and destination, you can opt to use Maps Javascript APIs Directions Service. This API will enable you to make more dynamic changes in your map.
Here's a sample code and code snippet below:
function initMap() {
const directionsService = new google.maps.DirectionsService();
const directionsRenderer = new google.maps.DirectionsRenderer();
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 17,
center: {
lat: 22.572646,
lng: 88.363895
},
});
directionsRenderer.setMap(map);
calculateAndDisplayRoute(directionsService, directionsRenderer);
}
function calculateAndDisplayRoute(directionsService, directionsRenderer) {
directionsService
.route({
origin: 'rishra',
destination: 'kolkata',
travelMode: google.maps.TravelMode.DRIVING,
})
.then((response) => {
directionsRenderer.setDirections(response);
})
.catch((e) => window.alert("Directions request failed due to " + status));
}

initializing 'marker-animate-unobtrusive' in Vue fails

I am trying to use marker-animate-unobtrusive but I keep getting this error:
I found another post on SO that talked about requiring the file after google has loaded but I do not know how to do that. in my component I have this:
import SlidingMarker from 'marker-animate-unobtrusive'
In my mounted method I have this:
SlidingMarker.initializeGlobally()
Any help is greatly appreciated
This is expected error since SlidingMarker extends google.maps.Marker class, GoogleMaps JavaScript API library needs to be loaded first, one option would to add a reference via index.html file:
<script src="https://maps.googleapis.com/maps/api/js?key=--KEY-GOES-HERE--"></script>
Another option would to utilize async JavaScript loader, e.g. scriptjs. The example for loading GoogleMaps JavaScript API and marker-animate-unobtrusive module could look like this:
created: function(){
get("https://maps.googleapis.com/maps/api/js?key=", () => {
const SlidingMarker = require('marker-animate-unobtrusive')
SlidingMarker.initializeGlobally()
const map = new google.maps.Map(document.getElementById('map'), this.mapOptions);
const marker = new SlidingMarker({
position: this.mapOptions.center,
map: map,
title: 'Im sliding marker'
});
});
}
Here is a demo for your reference
Update
With vue-google-maps library marker-animate-unobtrusive plugin could be integrated like this:
<template>
<div>
<GmapMap :center="center" :zoom="zoom" ref="mapRef"></GmapMap>
</div>
</template>
<script>
/* global google */
export default {
data() {
return {
zoom: 12,
center: { lat: 51.5287718, lng: -0.2416804 },
};
},
mounted: function() {
this.$refs.mapRef.$mapPromise.then(() => {
this.initSlidingMarker(this.$refs.mapRef.$mapObject)
})
},
methods: {
initSlidingMarker(map){
const SlidingMarker = require('marker-animate-unobtrusive')
SlidingMarker.initializeGlobally()
const marker = new SlidingMarker({
position: map.getCenter(),
map: map,
title: 'Im sliding marker'
});
google.maps.event.addListener(map, 'click', (event) => {
marker.setDuration(1000);
marker.setEasing('linear');
marker.setPosition(event.latLng);
});
}
}
}
</script>
<style>
.vue-map-container {
height: 640px;
}
</style>
Install the package google from npm this should fix it.

Repeat function failed in Angular

For my Angular Project, I generated a geolocation component and want to repeat a function findMe() to show the current location.
Part of code in the component.ts is given as below.
...
export class GeolocationComponent implements OnInit{
#ViewChild('gmap') gmapElement: any;
map: google.maps.Map;
isTracking = false;
marker: google.maps.Marker;
constructor(public globalvar: GlobalvarService) { }
ngOnInit() {
var mapProp = {
center: new google.maps.LatLng(-27.542211, 153.1226333),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map(this.gmapElement.nativeElement, mapProp);
setInterval(this.findMe(), 3000);
}
findMe() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
this.showPosition(position);
console.log("find me");
});
} else {
alert("Geolocation is not supported by this browser.");
}
}
showPosition(position) {
this.globalvar.latitude = position.coords.latitude;
this.globalvar.longitude = position.coords.longitude;
let location = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
this.map.panTo(location);
if (!this.marker) {
this.marker = new google.maps.Marker({
position: location,
map: this.map,
title: 'Got you!'
});
}
else {
this.marker.setPosition(location);
}
}
...
In
ngOnInit(),
I use
setInterval(this.findMe(), 3000);
By checking the log, I see the findMe() is only called once, but not be repeated as that I expect.
I also tried changing findMe() ==> findMe
setInterval(this.findMe, 3000);
this time, the log repeatedly appears, however there is always a error:
ERROR TypeError: _this.showPosition is not a function
Could you please help how can I repeatedly calling findMe() and why the error happens?
The correct way to invoke the interval is with the function declaration setInterval(this.findMe, 3000);. As you noted, if you include the () it is only executed once.
One of the issues that comes up with setInterval is that it changes the this context of the executing function. To fix this, you need to force it to be constant.
constructor(public globalvar: GlobalvarService) {
this.findMe = this.findMe.bind(this);
}
Additional info:
Documentation
StackOverflow Question
You can just use an arrow function that preserves this context :
setInterval(() => this.findMe(), 3000);
You can use arrow function syntax to make it work.
ngOnInit() {
setInterval(() => {
this.findMe()
}, 4000);
}
findMe = () => {
console.log('found');
}
Arrow function is referencing this as Component at all times.
Example - https://stackblitz.com/edit/angular-wkv2he
Try
setInterval(() => {
this.findMe()
}, 3000);
But I think than better solution is to use Observable interval.
interval(3000).subscribe(res => {
this.findMe()
})
Or in older versions of Angular :)
Observable.interval(3000).subscribe(res => {
this.findMe()
})

Removing directions overlay using angular-google-maps and angular2

Im using an api to populate a map with several markers, my desired functionality is for a user to click a button associated with a marker and it would plot directions from their current location. On the first instance it works perfectly but the current directions plotted just remain when trying to change the coordinates
Im using angular2-google-maps to plot the markers but I had to find a custom directive for directions. I think the problem is that I need to destroy the instance of the directions but using ngIf didnt help. I also tried resetting the instance of the direction in my directive using directionsDisplay.set('directions', null); but that didnt work either
/* directions.directive.ts */
import {GoogleMapsAPIWrapper} from '#agm/core/services/google-maps-api-wrapper';
import { Directive, Input} from '#angular/core';
declare var google: any;
#Directive({
selector: '<agm-map-directions [origin]="origin" [destination]="destination" #test></agm-map-directions>'
})
export class DirectionsMapDirective {
#Input() origin;
#Input() destination;
constructor (private gmapsApi: GoogleMapsAPIWrapper) {}
ngOnInit(){
this.gmapsApi.getNativeMap().then(map => {
var directionsService = new google.maps.DirectionsService;
var directionsDisplay = new google.maps.DirectionsRenderer;
console.log("test");
directionsDisplay.setMap(map);
directionsService.route({
origin: {lat: this.origin.latitude, lng: this.origin.longitude},
destination: {lat: this.destination.latitude, lng: this.destination.longitude},
waypoints: [],
optimizeWaypoints: true,
travelMode: 'DRIVING'
}, function(response, status) {
if (status === 'OK') {
directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
});
}
}
Here is the html associated with it
<agm-map [zoom]="13" [latitude]="currentLocation.result.latitude" [longitude]="currentLocation.result.longitude">
<agm-marker [latitude]="currentLocation.result.latitude" [longitude]="currentLocation.result.latitude"></agm-marker>
<agm-marker *ngFor="let device of location.ChargeDevice; let i = index"
ngShow="device.SubscriptionRequiredFlag"
[latitude]="convertStringToNumber(device.ChargeDeviceLocation.Latitude)"
[longitude]="convertStringToNumber(device.ChargeDeviceLocation.Longitude)"
(markerClick)="clickedMarker(device)">
</agm-marker>
<div *ngIf="showDirections" >
<agm-map-directions [origin]="origin" [destination]="destination" #test></agm-map-directions>
</div>
</agm-map>
I had the same problem as you.
I solved it by creating a global object that holds the instantiation of directionsService and directionsDisplay, to be able to pass those as reference later. ( See javascript pass by reference )
public directions: any = {
directionsService: null,
directionsDisplay: null
}
Then, I created a function that initialize the map once and I called it within ngOnInit() function:
constructor(private _gmapsApi: GoogleMapsAPIWrapper) { }
ngOnInit() {
this.initalizeMap(this.directions);
}
initalizeMap(directions): void {
this._gmapsApi.getNativeMap().then(map => {
directions.directionsService = new google.maps.DirectionsService;
directions.directionsDisplay = new google.maps.DirectionsRenderer;
directions.directionsDisplay.setMap(map);
directions.directionsDisplay.addListener('directions_changed', function() {
this.displayRoute(this.origin, this.destination, directions.directionsService, directions.directionsDisplay);
});
this.displayRoute(this.origin, this.destination, directions.directionsService, directions.directionsDisplay);
})
}
I added a listener to directionsDisplay to displayRoute whenever a change is made in the directions. The function displayRoute take as parameters origin and destination passed through #Input and references to directionsService and directionsDisplay whose instances I saved in directions object. The waypoints I took are also through #Input.
displayRoute(origin, destination, service, display): void {
var myWaypoints = [];
for (var i = 0; i < this.waypoints.length; i++) {
console.log(this.waypoints[i].markerID);
console.log(this.waypoints[i].location);
}
for (var i = 0; i < this.waypoints.length; i++) {
myWaypoints.push({
location: new google.maps.LatLng(this.waypoints[i].location),
stopover: true
})
}
service.route({
origin: origin,
destination: destination,
waypoints: myWaypoints,
travelMode: 'WALKING',
avoidTolls: true
}, function(response, status) {
if (status === 'OK') {
console.log("Route OK.");
display.setDirections(response);
} else {
alert('Could not display directions due to: ' + status);
}
});
}
The last function and the most important is calculateRoute, which I call from the component I injected the service ( Map Component in my case ) whenever I want it to recalculate the route.
calculateRoute(): void {
this._gmapsApi.getNativeMap().then(map => {
this.displayRoute(this.origin, this.destination, this.directions.directionsService, this.directions.directionsDisplay);
});
}
Hope it helps!

React.js, where to put google maps api queries?

I'm building a google maps app with React.js.
My instinct is to create separate file with an ES6 class to handle search queries - within the class there will be a function that returns the search result. I intend to call that function from within a React Component.
See the component below for reference.
Should I move the code inside the findRoutes() and drawBoxes() methods to separate files? This is my first react app - want to learn how to best organize the code. Any tips are hugely appreciated.
var MapControl = React.createClass({
getInitialState: function(){
return {
originId: '',
destinationId: '',
radius: 1,
search: '',
map: {},
travelMode: google.maps.TravelMode.DRIVING
}
},
handleFormSubmit: function(input){
// Form Input
// Call findRoutes() once setState is complete.
this.setState({
originId: input.originId,
destinationId: input.destinationId,
radius: input.radius,
search: input.search
}, this.findRoutes);
},
handleMapRender: function(map){
// Intialized Google Map
this.setState({map: map});
directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer();
routeBoxer = new RouteBoxer();
directionsDisplay.setMap(map);
placesService = new google.maps.places.PlacesService(map);
},
findRoutes: function(){
var me = this;
if (!this.state.originId || !this.state.destinationId) {
alert("findRoutes!");
return;
}
directionsService.route({
origin: {'placeId': this.state.originId},
destination: {'placeId': this.state.destinationId},
travelMode: this.state.travelMode
}, _.bind(function(response, status){
if (status === google.maps.DirectionsStatus.OK) {
// me.response = response;
directionsDisplay.setDirections(response);
var path = response.routes[0].overview_path;
this.setState({
routes: response,
boxes: routeBoxer.box(path, this.state.radius)
},this.drawBoxes);
} else {
window.alert('Directions config failed due to ' + status);
}
}, this));
},
drawBoxes: function(){
var boxpolys = new Array(this.state.boxes.length);
for (var i = 0; i < this.state.boxes.length; i++) {
boxpolys[i] = new google.maps.Rectangle({
bounds: this.state.boxes[i],
fillOpacity: 0,
strokeOpacity: 1.0,
strokeColor: '#000000',
strokeWeight: 1,
map: this.state.map
});
}
},
render: function() {
return (
<div className="MapControl">
<h1>Search</h1>
<MapForm
onFormSubmit={this.handleFormSubmit}
map={this.state.map}/>
<GMap
setMapState={this.handleMapRender}
originId= {this.state.originId}
destinationId= {this.state.destinationId}
radius= {this.state.radius}
search= {this.state.search}/>
</div>
);
}
});
Your instinct is correct, in general it's good practice to keep your view code as minimal as possible, and to move anything that is not explicitly related to rendering your view into another class.
React.js itself is not opinionated as to how you handle the rest of your application needs but a few libraries have emerged as the leading solutions for handling events, routing, services, data, etc.
You should review the Flux pattern for an overview of how you might manage the rest of your applications needs for React apps.
https://facebook.github.io/flux/docs/overview.html
I've moved on from Flux to using Redux recently
http://redux.js.org/ (which has emerged as the leading 'Fluxish' state management lib)
If you want to just get something up and running quickly and aren't trying to dive into all that just yet, I'd move the findRoutes method to an external service that you import in... drawBoxes seems fine to keep in here as it is directly related to rendering map elements in the view

Categories

Resources