Related
ive got a component where i try to make some sort of magnetic snap scroll. i know the css usual css way of snap-y, and setting snap behavior to smooth, but the snap is too fast. so i tried on my own to create a component where if the app detects a scroll down or up with the function, and a scroll below
const [scrollDir, setScrollDir] = useState("");
const [index, setIndex] = useState("0")
useEffect(() => {
const threshold = 0;
let lastScrollY = window.pageYOffset;
let ticking = false;
const updateScrollDir = () => {
const scrollY = window.pageYOffset;
if (Math.abs(scrollY - lastScrollY) < threshold) {
ticking = false;
return;
}
if(scrollY>lastScrollY){
// setScrollDir("scrolling down")
scroller.scrollTo('about',{
duration: 1000,
delay: 100,
smooth: 'linear',
})
}
// setScrollDir(scrollY > lastScrollY ? "scrolling down" : "scrolling up");
lastScrollY = scrollY > 0 ? scrollY : 0;
ticking = false;
};
const onScroll = () => {
if (!ticking) {
window.requestAnimationFrame(updateScrollDir);
ticking = true;
}
};
window.addEventListener("scroll", onScroll);
console.log(scrollDir);
return () => window.removeEventListener("scroll", onScroll);
}, [scrollDir]);
the magnetic scroll doesnt work, the page goes all jumpy. i could add a global css to make smooth scrolling, but that defeats the purpose of giving easein animation of scrolling. is there a way to work around this?
When I'm taking an photo with my Windows Phone the landscape mode, it's perfect. The problem occurs when I'm taking a photo in portrait mode.
The photo gets rotated 90 degrees. It even occurs in the simulator as shown below.
Now this doesn't occur on Android or iOS so I assume this is because Windows is using the CameraProxy.js instead of/from cordova-plugin-camera.
My entire CameraProxy.js (Giant file, does contain 'rotate' stuff but method names are only about videos)
cordova.define("cordova-plugin-camera.CameraProxy", function(require, exports, module) {
var Camera = require('./Camera');
var getAppData = function () {
return Windows.Storage.ApplicationData.current;
};
var encodeToBase64String = function (buffer) {
return Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
};
var OptUnique = Windows.Storage.CreationCollisionOption.generateUniqueName;
var CapMSType = Windows.Media.Capture.MediaStreamType;
var webUIApp = Windows.UI.WebUI.WebUIApplication;
var fileIO = Windows.Storage.FileIO;
var pickerLocId = Windows.Storage.Pickers.PickerLocationId;
module.exports = {
// args will contain :
// ... it is an array, so be careful
// 0 quality:50,
// 1 destinationType:Camera.DestinationType.FILE_URI,
// 2 sourceType:Camera.PictureSourceType.CAMERA,
// 3 targetWidth:-1,
// 4 targetHeight:-1,
// 5 encodingType:Camera.EncodingType.JPEG,
// 6 mediaType:Camera.MediaType.PICTURE,
// 7 allowEdit:false,
// 8 correctOrientation:false,
// 9 saveToPhotoAlbum:false,
// 10 popoverOptions:null
// 11 cameraDirection:0
takePicture: function (successCallback, errorCallback, args) {
var sourceType = args[2];
if (sourceType != Camera.PictureSourceType.CAMERA) {
takePictureFromFile(successCallback, errorCallback, args);
} else {
takePictureFromCamera(successCallback, errorCallback, args);
}
}
};
// https://msdn.microsoft.com/en-us/library/windows/apps/ff462087(v=vs.105).aspx
var windowsVideoContainers = [".avi", ".flv", ".asx", ".asf", ".mov", ".mp4", ".mpg", ".rm", ".srt", ".swf", ".wmv", ".vob"];
var windowsPhoneVideoContainers = [".avi", ".3gp", ".3g2", ".wmv", ".3gp", ".3g2", ".mp4", ".m4v"];
// Default aspect ratio 1.78 (16:9 hd video standard)
var DEFAULT_ASPECT_RATIO = '1.8';
// Highest possible z-index supported across browsers. Anything used above is converted to this value.
var HIGHEST_POSSIBLE_Z_INDEX = 2147483647;
// Resize method
function resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType) {
var tempPhotoFileName = "";
var targetContentType = "";
if (encodingType == Camera.EncodingType.PNG) {
tempPhotoFileName = "camera_cordova_temp_return.png";
targetContentType = "image/png";
} else {
tempPhotoFileName = "camera_cordova_temp_return.jpg";
targetContentType = "image/jpeg";
}
var storageFolder = getAppData().localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting)
.then(function (storageFile) {
return fileIO.readBufferAsync(storageFile);
})
.then(function(buffer) {
var strBase64 = encodeToBase64String(buffer);
var imageData = "data:" + file.contentType + ";base64," + strBase64;
var image = new Image();
image.src = imageData;
image.onload = function() {
var ratio = Math.min(targetWidth / this.width, targetHeight / this.height);
var imageWidth = ratio * this.width;
var imageHeight = ratio * this.height;
var canvas = document.createElement('canvas');
var storageFileName;
canvas.width = imageWidth;
canvas.height = imageHeight;
canvas.getContext("2d").drawImage(this, 0, 0, imageWidth, imageHeight);
var fileContent = canvas.toDataURL(targetContentType).split(',')[1];
var storageFolder = getAppData().localFolder;
storageFolder.createFileAsync(tempPhotoFileName, OptUnique)
.then(function (storagefile) {
var content = Windows.Security.Cryptography.CryptographicBuffer.decodeFromBase64String(fileContent);
storageFileName = storagefile.name;
return fileIO.writeBufferAsync(storagefile, content);
})
.done(function () {
successCallback("ms-appdata:///local/" + storageFileName);
}, errorCallback);
};
})
.done(null, function(err) {
errorCallback(err);
}
);
}
function takePictureFromFile(successCallback, errorCallback, args) {
// Detect Windows Phone
if (navigator.appVersion.indexOf('Windows Phone 8.1') >= 0) {
takePictureFromFileWP(successCallback, errorCallback, args);
} else {
takePictureFromFileWindows(successCallback, errorCallback, args);
}
}
function takePictureFromFileWP(successCallback, errorCallback, args) {
var mediaType = args[6],
destinationType = args[1],
targetWidth = args[3],
targetHeight = args[4],
encodingType = args[5];
var filePickerActivationHandler = function(eventArgs) {
if (eventArgs.kind === Windows.ApplicationModel.Activation.ActivationKind.pickFileContinuation) {
var file = eventArgs.files[0];
if (!file) {
errorCallback("User didn't choose a file.");
webUIApp.removeEventListener("activated", filePickerActivationHandler);
return;
}
if (destinationType == Camera.DestinationType.FILE_URI || destinationType == Camera.DestinationType.NATIVE_URI) {
if (targetHeight > 0 && targetWidth > 0) {
resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType);
}
else {
var storageFolder = getAppData().localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).done(function (storageFile) {
if(destinationType == Camera.DestinationType.NATIVE_URI) {
successCallback("ms-appdata:///local/" + storageFile.name);
}
else {
successCallback(URL.createObjectURL(storageFile));
}
}, function () {
errorCallback("Can't access localStorage folder.");
});
}
}
else {
if (targetHeight > 0 && targetWidth > 0) {
resizeImageBase64(successCallback, errorCallback, file, targetWidth, targetHeight);
} else {
fileIO.readBufferAsync(file).done(function (buffer) {
var strBase64 =encodeToBase64String(buffer);
successCallback(strBase64);
}, errorCallback);
}
}
webUIApp.removeEventListener("activated", filePickerActivationHandler);
}
};
var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker();
if (mediaType == Camera.MediaType.PICTURE) {
fileOpenPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]);
fileOpenPicker.suggestedStartLocation = pickerLocId.picturesLibrary;
}
else if (mediaType == Camera.MediaType.VIDEO) {
fileOpenPicker.fileTypeFilter.replaceAll(windowsPhoneVideoContainers);
fileOpenPicker.suggestedStartLocation = pickerLocId.videosLibrary;
}
else {
fileOpenPicker.fileTypeFilter.replaceAll(["*"]);
fileOpenPicker.suggestedStartLocation = pickerLocId.documentsLibrary;
}
webUIApp.addEventListener("activated", filePickerActivationHandler);
fileOpenPicker.pickSingleFileAndContinue();
}
function takePictureFromFileWindows(successCallback, errorCallback, args) {
var mediaType = args[6],
destinationType = args[1],
targetWidth = args[3],
targetHeight = args[4],
encodingType = args[5];
var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker();
if (mediaType == Camera.MediaType.PICTURE) {
fileOpenPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]);
fileOpenPicker.suggestedStartLocation = pickerLocId.picturesLibrary;
}
else if (mediaType == Camera.MediaType.VIDEO) {
fileOpenPicker.fileTypeFilter.replaceAll(windowsVideoContainers);
fileOpenPicker.suggestedStartLocation = pickerLocId.videosLibrary;
}
else {
fileOpenPicker.fileTypeFilter.replaceAll(["*"]);
fileOpenPicker.suggestedStartLocation = pickerLocId.documentsLibrary;
}
fileOpenPicker.pickSingleFileAsync().done(function (file) {
if (!file) {
errorCallback("User didn't choose a file.");
return;
}
if (destinationType == Camera.DestinationType.FILE_URI || destinationType == Camera.DestinationType.NATIVE_URI) {
if (targetHeight > 0 && targetWidth > 0) {
resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType);
}
else {
var storageFolder = getAppData().localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).done(function (storageFile) {
if(destinationType == Camera.DestinationType.NATIVE_URI) {
successCallback("ms-appdata:///local/" + storageFile.name);
}
else {
successCallback(URL.createObjectURL(storageFile));
}
}, function () {
errorCallback("Can't access localStorage folder.");
});
}
}
else {
if (targetHeight > 0 && targetWidth > 0) {
resizeImageBase64(successCallback, errorCallback, file, targetWidth, targetHeight);
} else {
fileIO.readBufferAsync(file).done(function (buffer) {
var strBase64 =encodeToBase64String(buffer);
successCallback(strBase64);
}, errorCallback);
}
}
}, function () {
errorCallback("User didn't choose a file.");
});
}
function takePictureFromCamera(successCallback, errorCallback, args) {
// Check if necessary API available
if (!Windows.Media.Capture.CameraCaptureUI) {
takePictureFromCameraWP(successCallback, errorCallback, args);
} else {
takePictureFromCameraWindows(successCallback, errorCallback, args);
}
}
function takePictureFromCameraWP(successCallback, errorCallback, args) {
// We are running on WP8.1 which lacks CameraCaptureUI class
// so we need to use MediaCapture class instead and implement custom UI for camera
var destinationType = args[1],
targetWidth = args[3],
targetHeight = args[4],
encodingType = args[5],
saveToPhotoAlbum = args[9],
cameraDirection = args[11],
capturePreview = null,
cameraCaptureButton = null,
cameraCancelButton = null,
capture = null,
captureSettings = null,
CaptureNS = Windows.Media.Capture,
sensor = null;
}
function continueVideoOnFocus() {
// if preview is defined it would be stuck, play it
if (capturePreview) {
capturePreview.play();
}
}
function startCameraPreview() {
// Search for available camera devices
// This is necessary to detect which camera (front or back) we should use
var DeviceEnum = Windows.Devices.Enumeration;
var expectedPanel = cameraDirection === 1 ? DeviceEnum.Panel.front : DeviceEnum.Panel.back;
// Add focus event handler to capture the event when user suspends the app and comes back while the preview is on
window.addEventListener("focus", continueVideoOnFocus);
DeviceEnum.DeviceInformation.findAllAsync(DeviceEnum.DeviceClass.videoCapture).then(function (devices) {
if (devices.length <= 0) {
destroyCameraPreview();
errorCallback('Camera not found');
return;
}
devices.forEach(function(currDev) {
if (currDev.enclosureLocation.panel && currDev.enclosureLocation.panel == expectedPanel) {
captureSettings.videoDeviceId = currDev.id;
}
});
captureSettings.photoCaptureSource = Windows.Media.Capture.PhotoCaptureSource.photo;
return capture.initializeAsync(captureSettings);
}).then(function () {
// create focus control if available
var VideoDeviceController = capture.videoDeviceController;
var FocusControl = VideoDeviceController.focusControl;
if (FocusControl.supported === true) {
capturePreview.addEventListener('click', function () {
// Make sure function isn't called again before previous focus is completed
if (this.getAttribute('clicked') === '1') {
return false;
} else {
this.setAttribute('clicked', '1');
}
var preset = Windows.Media.Devices.FocusPreset.autoNormal;
var parent = this;
FocusControl.setPresetAsync(preset).done(function () {
// set the clicked attribute back to '0' to allow focus again
parent.setAttribute('clicked', '0');
});
});
}
// msdn.microsoft.com/en-us/library/windows/apps/hh452807.aspx
capturePreview.msZoom = true;
capturePreview.src = URL.createObjectURL(capture);
capturePreview.play();
// Bind events to controls
sensor = Windows.Devices.Sensors.SimpleOrientationSensor.getDefault();
if (sensor !== null) {
sensor.addEventListener("orientationchanged", onOrientationChange);
}
// add click events to capture and cancel buttons
cameraCaptureButton.addEventListener('click', onCameraCaptureButtonClick);
cameraCancelButton.addEventListener('click', onCameraCancelButtonClick);
// Change default orientation
if (sensor) {
setPreviewRotation(sensor.getCurrentOrientation());
} else {
setPreviewRotation(Windows.Graphics.Display.DisplayInformation.getForCurrentView().currentOrientation);
}
// Get available aspect ratios
var aspectRatios = getAspectRatios(capture);
// Couldn't find a good ratio
if (aspectRatios.length === 0) {
destroyCameraPreview();
errorCallback('There\'s not a good aspect ratio available');
return;
}
// add elements to body
document.body.appendChild(capturePreview);
document.body.appendChild(cameraCaptureButton);
document.body.appendChild(cameraCancelButton);
if (aspectRatios.indexOf(DEFAULT_ASPECT_RATIO) > -1) {
return setAspectRatio(capture, DEFAULT_ASPECT_RATIO);
} else {
// Doesn't support 16:9 - pick next best
return setAspectRatio(capture, aspectRatios[0]);
}
}).done(null, function (err) {
destroyCameraPreview();
errorCallback('Camera intitialization error ' + err);
});
}
function destroyCameraPreview() {
// If sensor is available, remove event listener
if (sensor !== null) {
sensor.removeEventListener('orientationchanged', onOrientationChange);
}
// Pause and dispose preview element
capturePreview.pause();
capturePreview.src = null;
// Remove event listeners from buttons
cameraCaptureButton.removeEventListener('click', onCameraCaptureButtonClick);
cameraCancelButton.removeEventListener('click', onCameraCancelButtonClick);
// Remove the focus event handler
window.removeEventListener("focus", continueVideoOnFocus);
// Remove elements
[capturePreview, cameraCaptureButton, cameraCancelButton].forEach(function (elem) {
if (elem /* && elem in document.body.childNodes */) {
document.body.removeChild(elem);
}
});
// Stop and dispose media capture manager
if (capture) {
capture.stopRecordAsync();
capture = null;
}
}
function getAspectRatios(capture) {
var videoDeviceController = capture.videoDeviceController;
var photoAspectRatios = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.photo).map(function (element) {
return (element.width / element.height).toFixed(1);
}).filter(function (element, index, array) { return (index === array.indexOf(element)); });
var videoAspectRatios = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.videoRecord).map(function (element) {
return (element.width / element.height).toFixed(1);
}).filter(function (element, index, array) { return (index === array.indexOf(element)); });
var videoPreviewAspectRatios = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.videoPreview).map(function (element) {
return (element.width / element.height).toFixed(1);
}).filter(function (element, index, array) { return (index === array.indexOf(element)); });
var allAspectRatios = [].concat(photoAspectRatios, videoAspectRatios, videoPreviewAspectRatios);
var aspectObj = allAspectRatios.reduce(function (map, item) {
if (!map[item]) {
map[item] = 0;
}
map[item]++;
return map;
}, {});
return Object.keys(aspectObj).filter(function (k) {
return aspectObj[k] === 3;
});
}
function setAspectRatio(capture, aspect) {
// Max photo resolution with desired aspect ratio
var videoDeviceController = capture.videoDeviceController;
var photoResolution = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.photo)
.filter(function (elem) {
return ((elem.width / elem.height).toFixed(1) === aspect);
})
.reduce(function (prop1, prop2) {
return (prop1.width * prop1.height) > (prop2.width * prop2.height) ? prop1 : prop2;
});
// Max video resolution with desired aspect ratio
var videoRecordResolution = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.videoRecord)
.filter(function (elem) {
return ((elem.width / elem.height).toFixed(1) === aspect);
})
.reduce(function (prop1, prop2) {
return (prop1.width * prop1.height) > (prop2.width * prop2.height) ? prop1 : prop2;
});
// Max video preview resolution with desired aspect ratio
var videoPreviewResolution = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.videoPreview)
.filter(function (elem) {
return ((elem.width / elem.height).toFixed(1) === aspect);
})
.reduce(function (prop1, prop2) {
return (prop1.width * prop1.height) > (prop2.width * prop2.height) ? prop1 : prop2;
});
return videoDeviceController.setMediaStreamPropertiesAsync(CapMSType.photo, photoResolution)
.then(function () {
return videoDeviceController.setMediaStreamPropertiesAsync(CapMSType.videoPreview, videoPreviewResolution);
})
.then(function () {
return videoDeviceController.setMediaStreamPropertiesAsync(CapMSType.videoRecord, videoRecordResolution);
});
}
/**
* When the phone orientation change, get the event and change camera preview rotation
* #param {Object} e - SimpleOrientationSensorOrientationChangedEventArgs
*/
function onOrientationChange(e) {
setPreviewRotation(e.orientation);
}
/**
* Converts SimpleOrientation to a VideoRotation to remove difference between camera sensor orientation
* and video orientation
* #param {number} orientation - Windows.Devices.Sensors.SimpleOrientation
* #return {number} - Windows.Media.Capture.VideoRotation
*/
function orientationToRotation(orientation) {
// VideoRotation enumerable and BitmapRotation enumerable have the same values
// https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.capture.videorotation.aspx
// https://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmaprotation.aspx
switch (orientation) {
// portrait
case Windows.Devices.Sensors.SimpleOrientation.notRotated:
return Windows.Media.Capture.VideoRotation.clockwise90Degrees;
// landscape
case Windows.Devices.Sensors.SimpleOrientation.rotated90DegreesCounterclockwise:
return Windows.Media.Capture.VideoRotation.none;
// portrait-flipped (not supported by WinPhone Apps)
case Windows.Devices.Sensors.SimpleOrientation.rotated180DegreesCounterclockwise:
// Falling back to portrait default
return Windows.Media.Capture.VideoRotation.clockwise90Degrees;
// landscape-flipped
case Windows.Devices.Sensors.SimpleOrientation.rotated270DegreesCounterclockwise:
return Windows.Media.Capture.VideoRotation.clockwise180Degrees;
// faceup & facedown
default:
// Falling back to portrait default
return Windows.Media.Capture.VideoRotation.clockwise90Degrees;
}
}
/**
* Rotates the current MediaCapture's video
* #param {number} orientation - Windows.Devices.Sensors.SimpleOrientation
*/
function setPreviewRotation(orientation) {
capture.setPreviewRotation(orientationToRotation(orientation));
}
try {
createCameraUI();
startCameraPreview();
} catch (ex) {
errorCallback(ex);
}
}
function takePictureFromCameraWindows(successCallback, errorCallback, args) {
var destinationType = args[1],
targetWidth = args[3],
targetHeight = args[4],
encodingType = args[5],
allowCrop = !!args[7],
saveToPhotoAlbum = args[9],
WMCapture = Windows.Media.Capture,
cameraCaptureUI = new WMCapture.CameraCaptureUI();
cameraCaptureUI.photoSettings.allowCropping = allowCrop;
if (encodingType == Camera.EncodingType.PNG) {
cameraCaptureUI.photoSettings.format = WMCapture.CameraCaptureUIPhotoFormat.png;
} else {
cameraCaptureUI.photoSettings.format = WMCapture.CameraCaptureUIPhotoFormat.jpeg;
}
// decide which max pixels should be supported by targetWidth or targetHeight.
var maxRes = null;
var UIMaxRes = WMCapture.CameraCaptureUIMaxPhotoResolution;
var totalPixels = targetWidth * targetHeight;
if (targetWidth == -1 && targetHeight == -1) {
maxRes = UIMaxRes.highestAvailable;
}
// Temp fix for CB-10539
/*else if (totalPixels <= 320 * 240) {
maxRes = UIMaxRes.verySmallQvga;
}*/
else if (totalPixels <= 640 * 480) {
maxRes = UIMaxRes.smallVga;
} else if (totalPixels <= 1024 * 768) {
maxRes = UIMaxRes.mediumXga;
} else if (totalPixels <= 3 * 1000 * 1000) {
maxRes = UIMaxRes.large3M;
} else if (totalPixels <= 5 * 1000 * 1000) {
maxRes = UIMaxRes.veryLarge5M;
} else {
maxRes = UIMaxRes.highestAvailable;
}
cameraCaptureUI.photoSettings.maxResolution = maxRes;
var cameraPicture;
// define focus handler for windows phone 10.0
var savePhotoOnFocus = function () {
window.removeEventListener("focus", savePhotoOnFocus);
// call only when the app is in focus again
savePhoto(cameraPicture, {
destinationType: destinationType,
targetHeight: targetHeight,
targetWidth: targetWidth,
encodingType: encodingType,
saveToPhotoAlbum: saveToPhotoAlbum
}, successCallback, errorCallback);
};
cameraCaptureUI.captureFileAsync(WMCapture.CameraCaptureUIMode.photo).done(function (picture) {
if (!picture) {
errorCallback("User didn't capture a photo.");
// Remove the focus handler if present
window.removeEventListener("focus", savePhotoOnFocus);
return;
}
cameraPicture = picture;
// If not windows 10, call savePhoto() now. If windows 10, wait for the app to be in focus again
if (navigator.appVersion.indexOf('Windows Phone 10.0') < 0) {
savePhoto(cameraPicture, {
destinationType: destinationType,
targetHeight: targetHeight,
targetWidth: targetWidth,
encodingType: encodingType,
saveToPhotoAlbum: saveToPhotoAlbum
}, successCallback, errorCallback);
}
}, function () {
errorCallback("Fail to capture a photo.");
window.removeEventListener("focus", savePhotoOnFocus);
});
}
require("cordova/exec/proxy").add("Camera",module.exports);
});
Does anyone know how I can keep my image rotation in Windows?
In your CameraProxy.js make changes in orientationToRotation function line number 569.
case Windows.Devices.Sensors.SimpleOrientation.notRotated:
if (cameraDirection == 0) {
return Windows.Media.Capture.VideoRotation.clockwise90Degrees;
}
else {
return Windows.Media.Capture.VideoRotation.clockwise270Degrees;
}
For More Info you can refer this Solution
Exit app on double tap on back button in Nativescript
Please help me with snippet of code
Here is the solution that I have found:
var frameModule = require("ui/frame");
var application = require("application")
var activity = application.android.startActivity ||
application.android.foregroundActivity ||
frameModule.topmost().android.currentActivity ||
frameModule.topmost().android.activity;
var lastPress;
activity.onBackPressed = function() {
var timeDelay = 500
if (lastPress + timeDelay > java.lang.System.currentTimeMillis()) {
var startMain = new android.content.Intent(android.content.Intent.ACTION_MAIN);
startMain.addCategory(android.content.Intent.CATEGORY_HOME);
startMain.setFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(startMain);
// If you want to kill the app totally, use these codes instead of above
// activity.finish();
// java.lang.System.exit(0);
} else {
frameModule.topmost().goBack();
}
lastPress = java.lang.System.currentTimeMillis();
}
Hope this helps.
for Angular
import * as application from 'tns-core-modules/application';
exitapp=0
ngOnInit() {
application.android.on(application.AndroidApplication.activityBackPressedEvent, this.handleBackButton, this);
}
handleBackButton(args: any) {
this.ngZone.run(() => {
args.cancel = true;
if (this.routerExtensions.canGoBack()) {
this.routerExtensions.back();
}else{
this.exitapp++
this.getData.toast('Press again to exit')
if(this.exitapp==2){
application.android.foregroundActivity.finish();
}
setTimeout(()=>{
this.exitapp=0
},2000)
}
})
}
I am creating animations of migrating sea animals across the Pacific using OpenLayers. I would like each "animal" to trace a track as it goes over time. At the head of the track will be an icon/marker/overlay representing that animal. I have gotten this to work for one track, but although I am able to grow the track of each animal as a linestring constructed segment by segment, I am unable to specifically assign an icon/marker/overlay to each track. Instead, I am only able to animate one icon on one track. The rest of the linestring tracks proceed, but they do not have an icon at the head of the track as it is traced out. Here is my code. Any help appreciated.
// draw tracks
function makeLineString(id, species, multipointCoords, tracksTime) {
// layer structure and style assignment
var trackSource = new ol.source.Vector();
var trackLayer = new ol.layer.Vector({
source: trackSource,
style: BWtrackStyle
});
map.addLayer(trackLayer);
var lineString = new ol.geom.LineString([
ol.proj.fromLonLat(multipointCoords[0][0])
]);
var trackFeature = new ol.Feature({
geometry: lineString
});
if (species === "Blue Whale") {
trackFeature.setStyle([BWtrackStyle, shadowStyle]);
};
trackSource.addFeature(trackFeature);
// icon-marker-overlay styling
var BW2205005icon = document.getElementById('BW2205005icon');
var BW2205005marker = new ol.Overlay({
positioning: 'center-center',
offset: [0, 0],
element: BW2205005icon,
stopEvent: false
});
map.addOverlay(BW2205005marker);
var BW2205012icon = document.getElementById('BW2205012icon');
var BW2205012marker = new ol.Overlay({
positioning: 'center-center',
offset: [0, 0],
element: BW2205012icon,
stopEvent: false
});
map.addOverlay(BW2205012marker);
var coordinate, i = 1,
length = multipointCoords[0].length;
var currentTime = tracksTime[0][0];
var nextTime = tracksTime[0][1];
speedOption = 100; // the highter this value, the faster the tracks, see next line
var transitionTime = (nextTime - currentTime) / speedOption;
console.log(transitionTime);
var timer;
timer = setInterval(function() {
segmentConstruction(id, multipointCoords, tracksTime);
}, transitionTime);
function segmentConstruction(id, multipointCoords, tracksTime) {
coordinate = ol.proj.fromLonLat(multipointCoords[0][i]);
lineString.appendCoordinate(coordinate);
console.log(id);
if (id === "BW2205005") {
BW2205005marker.setPosition(coordinate);
} else {
BW2205012marker.setPosition(coordinate);
};
if (i >= length - 1) {
clearInterval(timer);
} else {
i++;
clearInterval(timer);
currentTime = tracksTime[0][i];
nextTime = tracksTime[0][i + 1];
transitionTime = (nextTime - currentTime) / speedOption;
timer = setInterval(function() {
segmentConstruction(id, multipointCoords, tracksTime);
}, transitionTime);
};
};
};
I would suggest this for animation of multiple markers with smooth movement, but it requires a delay for other styles:
var vehicles= [{ "curlon":77.654397, "curlat":12.959898, "prevlon":77.651951, "prevlat":12.951074 },{ "curlon":77.672936, "curlat":12.958100, "prevlon":77.649290, "prevlat":12.960024 }];
function push_data_for_multimarker(map,gps_obj)
{
destruct=false;
var getz = gps_obj;
var data_arry = [];
for (var i = 0, length = getz.length; i < length; i++)
{
gps_smooth_coordinates_generator(parseFloat(getz[i].prevlon),parseFloat(getz[i].prevlat),parseFloat(getz[i].curlon),parseFloat(getz[i].curlat));
}
}
function gps_smooth_coordinates_generator(map,sourcelon,sourcelat,destinationlon,destinationlat)
{
var vehicle_data=[];
var beginz=ol.proj.transform([sourcelon,sourcelat], 'EPSG:4326', 'EPSG:3857');
var endz=ol.proj.transform([destinationlon,destinationlat], 'EPSG:4326', 'EPSG:3857');
vehicle_data.push(beginz);
vehicle_data.push(endz);
var path= vehicle_data;
var genrated_positions = [];
for(var k = 1;k<path.length;k++)
{
var pointsNo = 1000;
var startPos = {};
startPos.lat = path[k-1][1];
startPos.lng = path[k-1][0];
var endPos = {};
endPos.lat = path[k][1];
endPos.lng = path[k][0];
var latDelta = (endPos.lat - startPos.lat) / pointsNo;
var lngDelta = (endPos.lng - startPos.lng) / pointsNo;
for (var i = 0; i < pointsNo; i++)
{
var curLat = startPos.lat + i * latDelta;
var curLng = startPos.lng + i * lngDelta;
var arr = [];
arr.push(curLng);
arr.push(curLat);
genrated_positions.push(arr);
}
}
animate_multiple_marker(genrated_positions);
}
function animate_multiple_marker(map,veh_croods)
{
var routeCoords = veh_croods;
var routeLength = routeCoords.length;
console.log("routeCoords"+routeCoords);
console.log("routeLength"+routeLength);
var geoMarker = new ol.Feature({
type: 'geoMarker',
geometry: new ol.geom.Point(routeCoords[0])
});
var off_style =new ol.style.Style({
image: new ol.style.Circle({
radius: 7,
snapToPixel: false,
fill: new ol.style.Fill({color: 'black'}),
stroke: new ol.style.Stroke({
color: 'white', width: 2
})
})
});
var now;
var animating = false;
var speed=20;
var moveFeature = function(event) {
var vectorContext = event.vectorContext;
var frameState = event.frameState;
if (animating) {
var elapsedTime = frameState.time - now;
var index = Math.round(speed * elapsedTime / 1000);
if (index >= routeLength) {
console.log("index>>"+index);
stopAnimation();
animating = false;
console.log("animation ends");
}
if(animating)
{
var currentPoint = new ol.geom.Point(routeCoords[index]);
var feature = new ol.Feature(currentPoint);
vectorContext.drawFeature(feature,off_style);
}
else
{}
if(destruct)
{
console.log("termination initiated");
stopAnimation();
//destruct=false;
}
else
{ }
}
else
{
console.log("Not amnimating!!");
}
// tell OL3 to continue the postcompose animation
map.render();
};
triggerz_animation();
function stopAnimation() {
animating = false;
caller=false;
//remove listener
map.un('postcompose', moveFeature);
}
function start_vehicles()
{
animating = true;
now = new Date().getTime();
map.on('postcompose', moveFeature);
map.render();
}
if(caller)
{
start_vehicles();
}
else
{
}
}
var caller=false;
var drive_vehicle;
function triggerz_animation()
{
caller=true;
}
var destruct=false;
function collapse_animation()
{
destruct=true;
}
with reference to
http://openlayers.org/en/latest/examples/feature-move-animation.html?q=animation
Let this be helpfull..Thank You
pass data as json to the function:
push_data_for_multimarker(map,vehicles);
I think your overlay is being reused for each line. In any case, it would probably be simpler and more performant to use a point feature instead of the overlay, as follows:
add a new style to your layer for points (circle, image, etc.)
add a point feature representing the head of each line
update the coordinates of the point feature when necessary
In other words, each animal would have a linestring and a point feature. The style on the layer would include the stroke style for the line and the icon style for the point.
You could also style the points independently by giving each point feature it's own style, or using a style function on the layer.
I'm facing a performance problem with Leaflet (version 0.7.3). I'm working with an OSM map that I use to display a bunch of CircleMarkers linked by decorated Polylines (with arrow pattern every 25px). Loading take a little time but the main problem is that when I zoom the map I start facing severe lag (from the zoom level 16) and, beyond a certain limit (say 18 most of the time), browser just freeze and eventually crash (tested with chrome and firefox). I tried with a bunch of 1,000 linked markers, then I dropped to a set of around 100, but still the same concern... Of course, with 10 markers or less I don't have any problem.
Did you already face a similar trouble? How can I optimize Leaflet performances so that I can use an accurate zoom (beyond level 16) with more than 100 linked CircleMarkers ? I also wonder why performances are dropping so badly when zooming, while marker amount stay the same...
Thank you in advance for your answers,
Lenalys.
Cannot get the PolylineDecorator plugin to work on jsfiddle.
But here is the code that generate markers :
Map initialization :
var map;
function initializeMap(){
"use strict";
var layer;
var layer2;
function layerUrl(key, layer) {
return "http://wxs.ign.fr/" + key
+ "/geoportail/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&"
+ "LAYER=" + layer + "&STYLE=normal&TILEMATRIXSET=PM&"
+ "TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg";
}
layer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png',
{
attribution: '© OpenStreetMap contributors',
maxZoom: 18
});
layer2 = L.tileLayer(
layerUrl(IGN_AMBIENTE_KEY, "GEOGRAPHICALGRIDSYSTEMS.MAPS"),
{attribution: '© IGN'}
);
var baseMaps = {
"Terrestre": layer,
"Bathymetrique": layer2
};
map = L.map('map', {
layers: [layer],
zoom: 8,
center: [42.152796, 9.139150],
zoomControl: false
});
L.control.layers(baseMaps).addTo(map);
//add zoom control with your options
L.control.zoom({
position:'topright' //topleft
}).addTo(map);
L.control.scale({
position:'bottomleft',
imperial : false
}).addTo(map);
}
Data Sample :
var jsonData ={"12":[{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657283333333","longitude":"9.42362","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 15:37:12"},
{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657381666667","longitude":"9.42365","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 16:42:16"},
{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657381666667","longitude":"9.4236933333333","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 17:47:21"},
{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657283333333","longitude":"9.4237383333333","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 19:57:23"}],
"13":[{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.61683","longitude":"9.4804633333333","temperature":"17.45","pulse":null,"battery":"80","date_time":"2015-04-08 07:45:20"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.538858333333","longitude":"9.48169","temperature":"14.37","pulse":null,"battery":"80","date_time":"2015-04-08 08:00:29"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.458748333333","longitude":"9.500225","temperature":"14.46","pulse":null,"battery":"80","date_time":"2015-04-08 08:15:49"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.3302","longitude":"9.5374583333333","temperature":"15.19","pulse":null,"battery":"80","date_time":"2015-04-08 08:31:05"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.170133333333","longitude":"9.5272116666667","temperature":"15.48","pulse":null,"battery":"80","date_time":"2015-04-08 08:46:20"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07959","longitude":"9.47688","temperature":"15.97","pulse":null,"battery":"80","date_time":"2015-04-08 09:01:31"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.076163333333","longitude":"9.4828633333333","temperature":"20.42","pulse":null,"battery":"80","date_time":"2015-04-08 09:16:59"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07194","longitude":"9.4908866666667","temperature":"17.36","pulse":null,"battery":"80","date_time":"2015-04-08 09:32:17"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.072583333333","longitude":"9.4901516666667","temperature":"17.36","pulse":null,"battery":"80","date_time":"2015-04-08 09:47:32"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07238","longitude":"9.4904266666667","temperature":"19.38","pulse":null,"battery":"80","date_time":"2015-04-08 10:02:42"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.072298333333","longitude":"9.4904983333333","temperature":"17.46","pulse":null,"battery":"80","date_time":"2015-04-08 10:17:55"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.095093333333","longitude":"9.5148383333333","temperature":"17.47","pulse":null,"battery":"80","date_time":"2015-04-08 10:33:12"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.112881666667","longitude":"9.5133133333333","temperature":"19.3","pulse":null,"battery":"80","date_time":"2015-04-08 10:48:23"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.112875","longitude":"9.513285","temperature":"22.71","pulse":null,"battery":"80","date_time":"2015-04-08 11:03:57"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.141096666667","longitude":"9.5078216666667","temperature":"23.73","pulse":null,"battery":"80","date_time":"2015-04-08 11:19:12"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.282186666667","longitude":"9.5505183333333","temperature":"18.97","pulse":null,"battery":"80","date_time":"2015-04-08 11:34:28"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.405126666667","longitude":"9.531145","temperature":"20.71","pulse":null,"battery":"80","date_time":"2015-04-08 11:49:42"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.482063333333","longitude":"9.480665","temperature":"21.7","pulse":null,"battery":"80","date_time":"2015-04-08 12:05:07"}]}
var oJSON = JSON.parse(jsonData);
var colors = [
"#400080",
"#008000",
"#EC7600",
"#E40341",
"#0D5E5E",
"#919191",
"#FF3C9D",
"#A70A0E",
"#00BFBF",
"#7171FF"
];
var classes = [
"color1",
"color2",
"color3",
"color4",
"color5",
"color6",
"color7",
"color8",
"color9",
"color10"
];
var lastMarkers = [];
var layers = new Array();
var polyline;
var decorator;
window.graphicsDevices = [];
var offsetLatitude = 0.003333;
var offsetLongitude = 0.011666;
Marker instanciation :
function printGPSOnMap(oJSON){
var nbKeys = 0;
for (var key in oJSON) {
nbKeys++;
var classe = classes[(key-1)%classes.length];
var color = colors[(key-1)%colors.length];
var positionInfo = [];
if (oJSON.hasOwnProperty(key)) {
var aInfo = oJSON[key];
var marker;
var latlngs = Array();
var startMarker = lastMarkers[key];
if(startMarker !== undefined && startMarker != null) {
var myIcon = L.divIcon({className: "myCircle "+classe, iconSize : [ 20, 20 ] });
startMarker.setIcon(myIcon);
latlngs.push(startMarker.getLatLng());
}
for(var i = 0; i < aInfo.length; i++) {
var oInfos = aInfo[i];
var sIdIndividual = oInfos["id_individual"];
var sLongitude = oInfos["longitude"];
var sLatitude = oInfos["latitude"];
var sTemperature = oInfos["temperature"];
var sPulse = oInfos["pulse"];
var sBattery = oInfos["battery"];
var sDatetime = oInfos["date_time"];
var sIndividualName = oInfos["individual_name"];
var id_device = oInfos["id_stm_device"];
var popupMsg = "...";
latlngs.push(L.marker([sLatitude,sLongitude]).getLatLng());
marker = new MyCustomMarker([sLatitude,sLongitude], {
icon : L.divIcon({
className : "myCircle "+classe + ((i == aInfo.length-1) ? ' myCircleEnd' : ''),
iconSize : [ 20, 20 ]
})
});
marker.bindPopup(popupMsg, {
showOnMouseOver: true
});
marker.bindLabel(key, {
noHide: true,
direction: 'middle',
offset: [offset[0], offset[1]]
});
positionInfo.push(marker);
}
lastMarkers[key] = marker;
}
if(latlngs.length > 1)
{
polyline = L.polyline(latlngs, {className: classe, weight: 2,opacity: 0.4}).addTo(map);
decorator = L.polylineDecorator(polyline, {
patterns: [
// define a pattern of 10px-wide arrows, repeated every 20px on the line
{offset: 0, repeat: '25px', symbol: new L.Symbol.arrowHead({pixelSize: 10, pathOptions: {fillOpacity:
0.76, color: color, weight: 1}})}
]}).addTo(map);
}
if(!window.graphicsDevices.hasOwnProperty(key))
window.graphicsDevices[key] = [];
for(var i = 0; i < positionInfo.length; i++) {
window.graphicsDevices[key].push(positionInfo[i]);
positionInfo[i].addTo(map);
if(latlngs.length > 1){
window.graphicsDevices[key].push(polyline);
polyline.addTo(map);
window.graphicsDevices[key].push(decorator);
decorator.addTo(map);
}
}
}//foreach key
}
Code for the custom marker :
var MyCustomMarker = L.Marker.extend({
bindPopup: function(htmlContent, options) {
if (options && options.showOnMouseOver) {
// call the super method
L.Marker.prototype.bindPopup.apply(this, [htmlContent, options]);
// unbind the click event
this.off("click", this.openPopup, this);
// bind to mouse over
this.on("mouseover", function(e) {
// get the element that the mouse hovered onto
var target = e.originalEvent.fromElement || e.originalEvent.relatedTarget;
var parent = this._getParent(target, "leaflet-popup");
// check to see if the element is a popup, and if it is this marker's popup
if (parent == this._popup._container)
return true;
// show the popup
this.openPopup();
}, this);
// and mouse out
this.on("mouseout", function(e) {
// get the element that the mouse hovered onto
var target = e.originalEvent.toElement || e.originalEvent.relatedTarget;
// check to see if the element is a popup
if (this._getParent(target, "leaflet-popup")) {
L.DomEvent.on(this._popup._container, "mouseout", this._popupMouseOut, this);
return true;
}
// hide the popup
this.closePopup();
}, this);
}
},
_popupMouseOut: function(e) {
// detach the event
L.DomEvent.off(this._popup, "mouseout", this._popupMouseOut, this);
// get the element that the mouse hovered onto
var target = e.toElement || e.relatedTarget;
// check to see if the element is a popup
if (this._getParent(target, "leaflet-popup"))
return true;
// check to see if the marker was hovered back onto
if (target == this._icon)
return true;
// hide the popup
this.closePopup();
},
_getParent: function(element, className) {
var parent = null;
if(element != null) parent = element.parentNode;
while (parent != null) {
if (parent.className && L.DomUtil.hasClass(parent, className))
return parent;
parent = parent.parentNode;
}
return false;
}
});
Have you gauged performance in canvas mode?
Use L_PREFER_CANVAS = true before initializing your leaflet map container.Might be able to help you possibly.