html2canvas not capturing images inside a react native webview - react-native

I want to capture the elements inside a WebView in react native.
This is the html of the WebView
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1" />
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossOrigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/html2canvas#1.4.1/dist/html2canvas.min.js" integrity="sha256-6H5VB5QyLldKH9oMFUmjxw2uWpPZETQXpCkBaDjquMs=" crossOrigin="anonymous"></script>
</head>
<body>
<div class="certificateDOM">
<div class="container-fluid">
<div class="row d-flex justify-content-center" id="certificateBlock">
<img
class="imageTemplate"
src="file:///android_asset/images/certificate1.png"
alt="certificate Image" />
<span class="certificateId"></span>
<span class="certificateName">is here by awarded the certification of achievement for the successfull completion of <b class='certificateBoldName'></b></span>
<span class="userName"></span>
<img class="certificateSign" src="file:///android_asset/images/authority1.png" alt="authority sign" />
</div>
</div>
</div>
</body>
</html>
This will look like this :
The student name and authority signature are absolutely positioned on the image (I have not included styles for these).
The image src is a 'file:///' url due to how android references the android assets.
This is the function which uses html2canvas to convert the element to a canvas:
const takeCertificateSnap = ()=>{
window.scrollTo(0, 0);
return html2canvas(document.querySelector('#certificateBlock'), {
allowTaint:true,
useCORS: true,
});
};
const getCertificateImageDataUrl = ()=>{
const canvasPromise = takeCertificateSnap();
canvasPromise.then((canvas) => {
const dataUrl = canvas.toDataURL();
const obj={
action:'getCertificateImageDataUrl',
data: {
dataUrl,
}
};
window.ReactNativeWebView.postMessage(JSON.stringify(obj));
}).catch((e) => {
const errmsg={
action:'error',
data: {
cause: 'html2canvas',
error: err.message,
}
};
window.ReactNativeWebView.postMessage(JSON.stringify(errmsg));
});
}
the image I am getting as a result of capturing the element as canvas and converting it to a dataUrl is this
Although the image is of same-origin, the image is not being rendered.
I saw couple of posts and included allowTaint and useCORS options, but it did not help.
Any help is appriciated.

Related

Problem with Materialize chips-autocomplete

I have been trying to get chips autocomplete to work as part of a project.
I have stripped code right back to remove any odd effects and replicated code as on the Materialize site. As in attached code I can get autocomplete to work as expected but not with chips.
I have tried with Chrome and Edge browsers and various combinations of tags and class names but still unable to make it work.
So now I need some help!
What have I missed?
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<div class="container" >
<!-- autocomplete from materialize web site -->
<div class="row">
<div class="col s12">
<div class="input-field col s6">
<i class="material-icons prefix">textsms</i>
<input type="text" id="autocomplete-input" class="autocomplete">
<label for="autocomplete-input">from materialize web site</label>
</div>
</div>
</div>
<!-- chip autocomplete from materialize web site -->
<div class="row">
<div class="col s6">
<div id="chips-autocomplete" class="chips chips-autocomplete " ></div>
</div>
</div>
</div> <!-- container end -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
options={"data": {"abel":null,"baker":null,"charlie":null},
"placeholder":'fred'}
console.log (options)
var autoElems = document.querySelectorAll('.autocomplete');
var attemptElems = document.getElementById("attempt");
var chipsElems = document.getElementById("chips-autocomplete");
var auto = M.Autocomplete.init(autoElems, options);
var chips = M.Chips.init(chipsElems, options);
});
</script>
</body>
</html>
The data init for chips-autocomplete is incorrect. From the docs:
$('.chips-autocomplete').chips({
autocompleteOptions: {
data: {
'Apple': null,
'Microsoft': null,
'Google': null
},
limit: Infinity,
minLength: 1
}
});
With Vanilla JS:
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.chips-autocomplete');
var instances = M.Chips.init(elems, {
autocompleteOptions: {
data: {
'Apple': null,
'Microsoft': null,
'Google': null
},
limit: Infinity,
minLength: 1
}
});
});
you are simply setting data (in quotes, when there should be no quotes). It should be autocompleteOptions as an object, and then data inside this.

WebRTC Remote Video Resolution(s) too large

I'm building a webrtc group video call, so far so good everything is working but the video resolution of the other users are too large. I've tried some solutions given on other questions like:
var video_constraints = {
mandatory: {
maxHeight: 480,
maxWidth: 640
},
optional: []
};
webrtc.mediaDevices.getUserMedia({
audio: true,
video: video_constraints
}, onsuccess);
But still no progress, instead my local video go blank. Here is my code:
HTML:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Group Video Call</title>
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<div class="container">
<!--============================ Main Starts
=============================================-->
<section>
<div class="ui container">
<div class="ui two column stackable grid">
<div class="ui ten wide column">
<div class="ui segment" id="segment">
<!--=========================== local camera =============================================-->
<div class="ui six wide column" id="local">
<img id="local-image" class="ui large image">
<video id="local-video" class="ui large image" autoplay></video>
</div>
</div>
</div>
<div class="video-actions">
<button value="submit" class="outBtn">Make room public</button>
<button value="submit" class="outBtn">Leave</button>
<button value="submit" id="muteBtn">Mute</button>
<button value="submit" class="outBtn">Kick</button>
</div>
<!--========================== reomte cameras
=============================================-->
<div id="remote-videos" class="ui stackable grid">
<div >
<img class="ui centered small image">
</div>
<div >
<img class="ui centered small image">
</div>
<div >
<img class="ui centered small image">
</div>
<div >
<img class="ui centered small image">
</div>
</div>
</div>
<!--======================== remote video template
=============================================-->
<script id="remote-video-template" type="text/x-handlebars-template">
<div id="{{ id }}" class="remote-img">
</div>
</script>
<div class="clr"></div>
</div>
</section>
</div>
<!--================================ scripts
==============================================-->
<script src="../functions/node_modules/jquery/dist/jquery.min.js"></script>
<script src="../functions/node_modules/handlebars/dist/handlebars.min.js ">
</script>
<script src="../functions/node_modules/simplewebrtc/out/simplewebrtc-with-
adapter.bundle.js"></script>
<script src="../functions/node_modules/semantic-ui-css/semantic.min.js">
</script>
<script src="js/app.js"></script>
</body>
</html>
JAVASCRIPT:
window.addEventListener('load', () => {
// for Group Creator Video
const localImageEl = $('#local-image');
const localVideoEl = $('#local-video');
// Joined Friends Videos
const remoteVideoTemplate = Handlebars.compile($('#remote-video-
template').html());
const remoteVideosEl = $('#remote-videos');
let remoteVideosCount = 0;
let height = 200;
let width = 200;
// Hiding cameras until they are initialized
localVideoEl.hide();
// initial rules for form verification
formEl.form({
fields: {
roomName: 'empty',
username: 'empty',
},
});
// create the webrtc connection
const webrtc = new SimpleWebRTC({
// the id dom element that will hold "our" video
localVideoEl: 'local-video',
// the id dom element that will hold remote videos
remoteVideosEl: 'remote-videos',
// for gaining video and voice access
autoRequestMedia: true,
debug: false,
detectSpeakingEvents: true,
autoAdjustMic: false,
});
// if (localCameraacess==1)
webrtc.on('localStream', () => {
localImageEl.hide();
localVideoEl.show();
});
// adding remote videos
webrtc.on('videoAdded', (video, peer) => {
// eslint-disable-next-line no-console
const id = webrtc.getDomId(peer);
const html = remoteVideoTemplate({ id });
if (remoteVideosCount < 5){
if (remoteVideosCount === 0) {
remoteVideosEl.html(html);
} else {
remoteVideosEl.append(html);
}
$(`#${id}`).html(video);
//$(`#${id} video`).addClass('ui image medium'); // for video
image to be responsive not good through
remoteVideosCount += 1;
}
});
// registeration of new chat room
const createRoom = (roomName) => {
console.info(`Creating new room: ${roomName}`);
webrtc.createRoom(roomName, (err, name) => {
formEl.form('clear');
showChatRoom(name);
postMessage(`${username} created chatroom`);
});
};
// Join existing Chat Room
const joinRoom = (roomName) => {
// eslint-disable-next-line no-console
console.log(`Joining Room: ${roomName}`);
webrtc.joinRoom(roomName);
showChatRoom(roomName);
postMessage(`${username} joined chatroom`);
};
});
I want to use a resolution of 320 x 240 on all remote video screens and also if i could get some code snippet on how to mute both VIDEO and AUDIO. And also leaving a connected peer. I appreciate any help.
Thanks for all the answers, but i found a fix from a question asked already:
WebRTC video constraints not working
All i did was place the code above the 'window' function and it worked.
Still don't know if it will work on firefox.

Leaflet map not loading in Bulma tab using Vue.js

I have an issue with loading Leaflet map using Vue.js and Bulma tab components (via Buefy).
If map is placed inside tab then it does not load all tiles until browser window is resized.
If map is placed outside of Bulma tabs component then it loads without any issue.
Calling map.invalidateSize() seems to help, but to do it automatically when tab changes I have to call it using setTimeout and put very big delay, like 1sec - which is very ugly.
How to get this working without this invalidateSize workaround?
Example with the issue: https://codepen.io/alxxnder/pen/zyYxwd
Example without the issue: https://codepen.io/alxxnder/pen/LMYEjr
Code:
new Vue({
el: '#app',
data: {
map: null,
},
methods: {
invalidateSize: function() {
this.map.invalidateSize();
}
},
mounted() {
this.map = L.map('map').setView([38.63, -90.23], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(this.map);
}
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Leaflet Test</title>
<link rel="stylesheet" href="https://unpkg.com/buefy#0.7/dist/buefy.min.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css">
</head>
<body>
<div class="section">
<div class="container" id="app">
<b-tabs position="is-centered">
<b-tab-item label="Tab 1">
<div class="section">
Tab 1
<div class="map" id="map" style="height: 400px; width: 100%"></div>
<button class="button is-info" #click="invalidateSize()">invalidateSize</button>
</div>
</b-tab-item>
<b-tab-item label="Tab 2">
<div class="section">
Tab 2
</div>
</b-tab-item>
</b-tabs>
</div>
</div>
</body>
<script src="https://unpkg.com/vue#2"></script>
<script src="https://unpkg.com/buefy#0.7/dist/buefy.min.js"></script>
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet.js"></script>
</html>
As explained in Data-toggle tab does not download Leaflet map, the issue is caused by the fact that your map container does not have yet its full size when you initialize it. You may understand it more easily if your map had been in an initially hidden tab (e.g. in tab 2).
As for your initially active tab (i.e. tab 1), it is probable that Buefy / Bulma still takes some time to reveal the tab content.
Since there is no event when the tab transition completes, you have to wait for the transition duration before calling the invalidateSize method. In your case, 300ms seems to be fine.
Then you should also call it again when the user changes the tab (see Buefy tabs events), otherwise should the browser had changed size while your tab was hidden, the same issue would happen again.
Demo with maps in the 2 tabs:
new Vue({
el: '#app',
data: {
map: null,
map2: null,
tabMaps: []
},
methods: {
invalidateSize: function(tabIndex) {
setTimeout(() => {
if (typeof tabIndex === "number") {
this.tabMaps[tabIndex].invalidateSize();
} else {
// invalidate all maps
this.tabMaps.forEach(map => {
map.invalidateSize();
});
}
}, 300);
}
},
mounted() {
this.map = L.map('map').setView([38.63, -90.23], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(this.map);
// map2 in tab2
this.map2 = L.map(this.$refs.map2).setView([38.63, -90.23], 12);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(
this.map2
);
this.tabMaps.push(this.map); // 0
this.tabMaps.push(this.map2); // 1
this.invalidateSize();
}
})
<link rel="stylesheet" href="https://unpkg.com/buefy#0.7/dist/buefy.min.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css">
<div class="section">
<div class="container" id="app">
<b-tabs #change="invalidateSize" position="is-centered">
<b-tab-item label="Tab 1">
<div class="section">
Tab 1
<div class="map" id="map" style="height: 400px; width: 100%"></div>
<button class="button is-info" #click="invalidateSize()">invalidateSize</button>
</div>
</b-tab-item>
<b-tab-item label="Tab 2">
<div class="section">
Tab 2
<div class="map" ref="map2" style="height: 400px; width: 100%"></div>
</div>
</b-tab-item>
</b-tabs>
</div>
</div>
<script src="https://unpkg.com/vue#2"></script>
<script src="https://unpkg.com/buefy#0.7/dist/buefy.min.js"></script>
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet.js"></script>

"Failed to generate render function" when i use tree component of ElementUI

I want to use Element UI in IE 11,and when i user the tree component,it creates errors.
It will create the error
Failed to generate render function:
SyntaxError 'missing in'
I want to show a icon before the text.But in IE 11,it errors while Chrome ok.
Anyone can tell me the problem..thx
the whole demo is
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>MLLRSJ</title>
<link rel="stylesheet" href="./Scripts/assets/Element/index.css">
<script src="./Scripts/assets/vue/vue.js"></script>
<script src="./Scripts/assets/Element/index.js"></script>
</head>
<body>
<div id='Element'>
<el-tree :data="tree" :props="treeProps">
<span slot-scope='{node,data}'>
<i class='el-icon-check'></i>
<span style="display:inline" v-html='node.label'></span>
</span>
</el-tree>
</div>
</body>
<script>
var vm = new Vue({
el:'#Element',
data:{
tree:[{
label:'1',
children:[{
label:'1-1'
}],
},
{
label:'2',
children:[
{
label:'2-1'
}
]
}
],
treeProps:{
label:'label',
children:'children'
}
}
})
</script>
</html>
Try to avoid curly braces(in slot-scope in your example) and arrow functions in inline templates if you work with IE11 (I had same problem in one of my projects):
<el-tree :data="tree" :props="treeProps">
<span slot-scope='someObject'>
<i class='el-icon-check'></i>
<span style="display:inline" v-html='someObject.node.label'></span>
</span>
</el-tree>

How to use an Observable object in a WinJS ListView

I want to use an observable object within a ListView in the Windows 8 RT (Developer Preview from BUILD 2011) (using JavaScript).
The code below seems like it should work. It has a simple template for displaying a title and a description of each object in the HTML and a basic use of the WinJS.UI.Listview component.
I expect to see a list of objects, but always see the "wait spinner" when the list contains observables.
Experimentally, I've noticed that if the code doesn't convert the entire list (all but 3) to observables, then the list will show up. From doing some debugging, it would appear that it's somehow timing related and that the WinJS framework miscounts and fails to render the ListView entirely (as some of the objects are "pending") for some reason (the miscount confusion happens deep in a call to realizeItems in the ScrollView code). If I comment out the enableFirstChanceException function call, it fails while comparing two objects (but I don't know if it's relevant) in the function itemChanged (circular reference in value argument not supported).
Any idea on how to make this work with observable objects?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=1024, height=768" />
<title>WinWebApp1</title>
<!-- WinJS references -->
<link rel="stylesheet" href="/winjs/css/ui-dark.css" />
<script type="text/javascript" src="/WinJS/js/base.js"></script>
<script type="text/javascript" src="/WinJS/js/ui.js"></script>
<script type="text/javascript" src="/WinJS/js/binding.js"></script>
<script type="text/javascript" src="/WinJS/js/controls.js"></script>
<script type="text/javascript" src="/WinJS/js/res.js"></script>
<script type="text/javascript" src="/WinJS/js/animations.js"></script>
<script type="text/javascript" src="/WinJS/js/uicollections.js"></script>
<script type="text/javascript" src="/WinJS/js/wwaapp.js"></script>
<!-- WinWebApp1 references -->
<link rel="stylesheet" href="/css/default.css" />
<script src="/js/default.js"></script>
</head>
<body>
<div id="itemTemplate" data-win-control="WinJS.Binding.Template" >
<div class="itemContainer">
<!-- Displays the "title" field. -->
<div class="itemTitle" data-win-bind="innerText: title">
</div>
<!-- Displays the "description" field. -->
<div class="itemDescription" data-win-bind="innerText: description">
</div>
</div>
</div>
<div data-win-control="WinJS.UI.ViewBox">
<div class="fixed-layout">
<div id="basicListView" data-win-control="WinJS.UI.ListView" data-win-options="{itemRenderer: itemTemplate}">
</div>
</div>
</div>
</body>
</html>
And the JavaScript:
(function () {
'use strict';
// Uncomment the following line to enable first chance exceptions.
//Debug.enableFirstChanceException(true);
var myData = [
{ title: "Banana", description: "Banana Frozen Yogurt"},
{ title: "Orange", description: "Orange Sherbet"},
{ title: "Vanilla", description: "Vanilla Ice Cream"},
{ title: "Mint", description: "Mint Gelato"},
{ title: "Strawberry", description: "Strawberry Sorbet"},
{ title: "Kiwi", description: "Kiwi Sorbet" }
];
// this works:
//var myDataSource = new WinJS.UI.ArrayDataSource(myData);
// this does not:
for (var i = 0; i < myData.length ; i++) {
myData[i] = WinJS.Binding.as(myData[i]);
}
var myDataSource = new WinJS.UI.ArrayDataSource(myData);
document.addEventListener("DOMContentLoaded", function (e) {
WinJS.UI.processAll()
.then(function () {
var basicListView = WinJS.UI.getControl(document.getElementById("basicListView"));
basicListView.dataSource = myDataSource;
// when the observable works correctly, this should work (and live change the list)
//setTimeout(function () {
// basicListView.refresh();
// myData[0].title = "Yellow Banana";
// myData[5].title = "Kiwisicle";
//}, 3000);
});
});
WinJS.Application.start();
})();