react native youtube view events - react-native

I want to record when the user press play on the youTube video that I embeded in my app using a web view.
I can't seem to find a way to get notified when the user start the video.
My webView's JSX:
<WebView
javaScriptEnabled={true}
domStorageEnabled={true}
source={{ uri: "https://www.youtube.com/embed/" + videoId }}
/>
Any pointers appreciated

For those coming here in the future I ended up using events posted from within the html that the webview picks up.
the JSX:
<WebView
style={{
height: carouselHeight,
width: width
}}
javaScriptEnabled={true}
domStorageEnabled={true}
source={{
html: youtubeHTML(videoId, width, carouselHeight)
}}
onMessage={event => {
//see ./data/youtube.js to see how this event is built
if (event.nativeEvent.data === "videoEvent_0") {
/************ do whatever you want on the event *************/
}
}}
/>
youTubeHTML():
function youtubeHTML(
videoID: string,
width: number,
height: number
) {
//see https://medium.com/capriza-engineering/communicating-between-react-native-and-the-webview-ac14b8b8b91a
const returnValue =
`<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0">
</head>
<body style="margin: 0px;background-color:#000;">
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="player"></div>
<script>
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '` +
height +
`',
width: '` +
width +
`',
videoId: '` +
videoID +
`',
events: {
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
window.postMessage("videoEvent_"+JSON.stringify(event.data))
}
</script>
</body>
</html>`;
return returnValue;
}

Related

How to get data out of a popup on a map with a feature layer from ArcGIS-api for javascript and reuse that data?

I am using a map with feature layers from ArcGIS and the popup to see some data when the user click on a symbol (feature). Is there a way to style the popups exactly the way we want ? In other words, how could I get the data out of the popup, not display the popup but open a modal with that data instead ? Is that even possible ?
This are actually two questions, can you style the popup?, and can you use your own "popup"?.
For the first one, I would say it is pretty customizable, but obviously it depends what you need.
For the second, you just need to stop the default behavior of the view popup, that is to open on right click, and then catch the event yourself to do what you want. Here is an example I made for you that shows that,
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
<title>PopupTemplate - Auto Open False</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.21/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.21/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 500px;
width: 100%;
}
#features {
margin: 20px;
height: 500px;
width: 100%;
overflow: auto;
}
</style>
<script>
var populationChange;
require(["esri/Map", "esri/views/MapView", "esri/layers/Layer"], function (
Map,
MapView,
Layer
) {
const map = new Map({
basemap: "dark-gray"
});
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 7,
center: [-87, 34]
});
Layer.fromPortalItem({
portalItem: {
id: "e8f85b4982a24210b9c8aa20ba4e1bf7"
}
}).then(function (layer) {
map.add(layer);
view.popup.autoOpenEnabled = false; // <- disable view popup auto open
view.on("click", function (event) { // <- listen to view click event
if (event.button === 0) { // <- check that was left button or touch
view.whenLayerView(layer).then(function (layerView) {
const query = layerView.layer.createQuery();
query.geometry = view.toMap(event);
query.distance = 1;
query.units = "meters";
layerView.queryFeatures(query).then(
response => {
document.getElementById("features").innerText = JSON.stringify(response.features);
console.error(response);
},
err => {
document.getElementById("features").innerText = "Query returns an error, check console to see what happen!.";
console.error(err);
}
);
});
}
});
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="features"></div>
</body>
</html>

ESRI Popup Maximize button missing

Currently working on showing a popup in the map using ESRI ArcGIS API for JavaScript 4.15.
But that is missing the Maximize button which was available with ArcGIS API for JavaScript 3.35
Is there any config to be set to show the same.
As far as I know the new API does not have that capability out of the box. But no worries, you can implement it by adding a custom action to the popup.
See the example I made for you to get an idea.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Popup actions | ArcGIS API for JavaScript 4.18</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.18/"></script>
<script>
require(["esri/Map", "esri/layers/FeatureLayer", "esri/views/MapView"], function (
Map,
FeatureLayer,
MapView
) {
const map = new Map({
basemap: "gray-vector"
});
const view = new MapView({
container: "viewDiv",
map: map,
center: [-117.08, 34.1],
zoom: 11
});
const toggleFullScreenAction = {
type: "toggle",
title: "Full Screen",
id: "toggle-full-screen",
className: "esri-icon-maximize"
};
view.popup.actions.add(toggleFullScreenAction);
const template = {
title: "Trail run",
content: "{name}"
};
featureLayer = new FeatureLayer({
url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/TrailRuns/FeatureServer/0",
outFields: ["*"],
popupTemplate: template
});
map.add(featureLayer);
function toggleFullScreen() {
if (!document.fullscreenElement) {
document.getElementsByClassName('esri-popup__main-container')[0].requestFullscreen()
.catch(err => {
alert(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
});
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
}
}
}
view.popup.on("trigger-action", function (event) {
if (event.action.id === "toggle-full-screen") {
toggleFullScreen();
}
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
To run the snippet, copy and save as an html file. The full screen action does not work in the snippet, I guess because it is embedded, not sure though.

arcGIS 4.18 locate widget custom icon

I have to change the default icon on the Locate widget on arcGIS 4.18. The default icon class is, esri-icon-locate how can I change it to the class, 'esri-icon-navigation'?
I am going through the documentation,
https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Locate.html#iconClass
I have tried to use the property, 'iconClass'. But not reflecting in the map icon. Please find the code below,
var locateBtn = new Locate({
view: view,
// iconClass: '\ue666'
iconClass: 'esri-icon-navigation'
});
view.ui.add(locateBtn, {
position: "manual",
});
KER,
You actually right, does not work as expected. Setting iconClass should be the solution.
Funny fact if you check the default iconClass is actually esri-icon-north-navigation, which obviously in not.
Anyway, I am gonna give a dirty solution, just overlap the class you want,
view.when(_ => {
const n = document.getElementsByClassName("esri-icon-locate");
if (n && n.length === 1) {
n[0].classList += " esri-icon-navigation"
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
<title>Locate button | Sample | ArcGIS API for JavaScript 4.18</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css" />
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script src="https://js.arcgis.com/4.18/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/widgets/Locate"
], function (Map, MapView, Locate) {
var map = new Map({
basemap: "topo-vector"
});
var view = new MapView({
container: "viewDiv",
map: map,
center: [-56.049, 38.485, 78],
zoom: 3
});
var locateBtn = new Locate({
view: view
});
// Add the locate widget to the top left corner of the view
view.ui.add(locateBtn, {
position: "top-left"
});
view.when(_ => {
const n = document.getElementsByClassName("esri-icon-locate");
if (n && n.length === 1) {
n[0].classList += " esri-icon-navigation"
}
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>

Take snapshot from webcam on website

I try to take snapshot from webcam on web browser. When I use this code below it works on mobile (Google Chrome on Android), but not on Google Chrome on Desktop. The video is not displayed. I get an error name: TrackStartError or DevicesNotFoundError. It was tested with external USB webcam.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Display Webcam Stream</title>
<style>
#container {
margin: 0 auto;
max-width: 480px;
}
video, img {
max-width: 100%;
background-color: #f2f3f5;
}
video {
height: 400px;
}
</style>
</head>
<body>
<div id="container">
<video autoplay></video>
</div>
<script>
var video = document.querySelector('video'), canvas;
function takeSnapshot() {
var img = document.querySelector('img') || document.createElement('img');
var context;
var width = video.offsetWidth, height = video.offsetHeight;
canvas = canvas || document.createElement('canvas');
canvas.width = width;
canvas.height = height;
context = canvas.getContext('2d');
context.drawImage(video, 0, 0, width, height);
img.src = canvas.toDataURL('image/png');
document.body.appendChild(img);
}
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
}
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
}
}
var constraints = {audio: false, video: {width: 640, height: 480}};
navigator.mediaDevices.getUserMedia(constraints)
.then(function (stream) {
if ("srcObject" in video) {
video.srcObject = stream;
} else {
video.src = window.URL.createObjectURL(stream);
}
video.onloadedmetadata = function (e) {
video.play();
};
video.addEventListener('click', takeSnapshot);
})
.catch(function (err) {
console.log(err.name + ": " + err.message);
});
</script>
</body>
</html>
I'm out of any options :(
What I'm doing wrong? It should work on most used desktop web browsers.
Try this (just work for videos):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="stuff, to, help, search, engines, not" name="keywords">
<meta content="What this page is about." name="description">
<meta content="Display Webcam Stream" name="title">
<title>Display Webcam Stream</title>
<style>
#container {
margin: 0px auto;
width: 500px;
height: 375px;
border: 10px #333 solid;
}
#videoElement {
width: 500px;
height: 375px;
background-color: #666;
}
</style>
</head>
<body>
<div id="container">
<video autoplay="true" id="videoElement">
</video>
</div>
<script>
var video = document.querySelector("#videoElement");
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({video: true})
.then(function(stream) {
video.srcObject = stream;
})
.catch(function(err0r) {
console.log("Something went wrong!");
});
}
</script>
</body>
</html>
Reference: https://www.kirupa.com/html5/accessing_your_webcam_in_html5.htm
Most probably your webcam or webcam drivers are not functioning correctly.
That's what the 2 errors that you're getting point to:
DevicesNotFoundError is a non spec error thrown by Chrome when you’re requesting a video track (through constraints) but a webcam is missing. The Firefox/spec equivalent is NotFoundError.
TrackStartError is a non spec error thrown by Chrome (on Windows) when the webcam is already in use by another app. The Firefox/spec equivalent is NotReadableError. The MDN description points to other causes as well:
Although the user granted permission to use the matching devices, a hardware error occurred at the operating system, browser, or Web page level which prevented access to the device
Source: Common getUserMedia() Errors

Youtube iFrame javascript API onYouTubeIframeAPIReady not firing

This is from the Youtube API docs:
"As mentioned in the Getting started section, instead of writing an empty element on your page, which the player API's JavaScript code will then replace with an element, you could create the tag yourself."
But I cannot get the API to callback to my javascript. Any help would be great.
Here's my HTML code:
<iframe id="player" type="text/html" width="640" height="360"src="http://www.youtube.com/embed/1_QO8LoGNpc?enablejsapi=1" frameborder="0"></iframe>
JAVASCRIPT:
<script>
function onYouTubeIframeAPIReady() {
alert("hey");
player = new YT.Player('player', {
// height: '720',
// width: '1280',
// videoId: '1_QO8LoGNpc',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
</script>
I can get it to work with using javascript creating the iframe but not setting the iframe on the page. HELP!
Function onYouTubeIframeAPIReady() should be defined before loading https://www.youtube.com/iframe_api.
Here is the idea:
<iframe id="player" type="text/html" width="640" height="360"src="http://www.youtube.com/embed/1_QO8LoGNpc?enablejsapi=1" frameborder="0"></iframe>
<script>
function onYouTubeIframeAPIReady() {
alert("hey");
player = new YT.Player('player', {
// height: '720',
// width: '1280',
// videoId: '1_QO8LoGNpc',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
</script>
<script src="https://www.youtube.com/iframe_api"></script>
Why? Because iframe_api will call this function after being loaded. In your case iframe_api was loaded before.
Best regards.
But your code works. See it here:
http://jsfiddle.net/aXLA2/
<iframe id="player" type="text/html" width="640" height="360"src="http://www.youtube.com/embed/1_QO8LoGNpc?enablejsapi=1" frameborder="0"></iframe>
<script src="https://www.youtube.com/iframe_api"></script>