Unable to download React Canvas Drawing - react-native

I want to download my drawing on the React canvas as a jpeg image file to my desktop, and then pass it to a python file for classification. Can someone specify a code to download the React canvas drawing, or suggest a better way to implement the idea?
clearCanvas({nativeEvent}) {
var image = this.canvas.toDataURL("image/jpeg");
nativeEvent.href=image;
this.ctx.save("C:/Users/PrishitaRay/Pictures/Myimage.jpeg");
this.ctx = this.canvas.getContext('2d');
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
This function just clears the react canvas without downloading it first.

After reading your code, I'm not sure if its related to React. Therefore I'm going to give a non-react solution.
In case you have done some drawing on the canvas like my exampleDrawing function, then just call download function like this.
function exampleDrawing(){
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0,0,150,75);
}
function download(){
var canvas = document.getElementById("canvas");
var url = canvas.toDataURL("image/png");
var link = document.createElement('a');
link.download = 'filename.png';
link.href = url;
link.click();
}
exampleDrawing();
<canvas id="canvas" width="200" height="100">
</canvas>
<button onclick="download();">Download!</button>
What my download function do is to create a URL that contains the canvas's image, generate a link, and then click on it.
And of course you don't have to generate a button and click on it. Just call the download function whenever you want.

Download Canvas as Image in React (Js only): (React Class Components)
Download As Image Function: chartRef.canvas gives the canvas element, replace it with your Canvas element.
handleChartDownload = (chartRef) => {
const chartCanvas = chartRef.canvas;
if (chartCanvas) {
const url = chartCanvas.toDataURL("image/png");
const link = document.createElement("a");
link.download = "chart.png";
link.href = url;
link.click();
}
};
Graph Element: these elements comes under render() function.
Download Button:
<button
className="btn btn-light"
onClick={() => this.handleChartDownload(this.chartRef)}
>Download</button>
Graph: (here Scatter is ChartJsReact component, used for creating graphs)
<Scatter
ref={(reference) => (this.chartRef = reference)}
data={this.state.chartData}
options={this.state.chartOptions}
/>

Related

Vue Leaflet Setting custom TileLayer bounds

I'm trying to display a large number of images using leaflet and I'm having problems making the tileLayers display properly.
I'm extending the TileLayer class and overriding the createTile function like this:
`
let imageLayer = TileLayer.extend({
createTile: function (coords, done) {
const image = window.L.DomUtil.create("img");
image.src = `http://placekitten.com/g/200/300`;
image.crossOrigin = "";
image.onload = function () {
this.onload = function () {};
done(null, image);
};
return image;
}
});
Result
I want to change the position of the images and to only display them in areas I have already defined (for example between offsetting the image at 0,0 to be at 1,1 or using latLng
([8273.300000000001, 10618.02] , [9232.653535353536, 9658.666464646465])).
Ive tried a bunch of different methods and almost always came back to bounds, which don't work and setting the bounds doesn't change anything.
I don't want to use ImageOverlays because the images I'm trying to display are sliced and named with the leaflet naming scheme (0_0_1.png).

How do I add custom image to mapbox marker?

const marker = document.createElement('div');
marker.innerHTML = `<img src="../../assets/FuelPin.png" style="height: 56px; width: 44px" alt=""/>`;
new mapboxgl.Marker(marker)
.setLngLat(lngLatPopup)
.addTo(this.map);
},
In the above code the src from img attribute is not loading the image. I tried using :src to bind as vue component but it is being rendered as string. My relative path to the image exists as well.
In general changing innerHTML with JavaScript is not something frameworks like Vue or React will let you do (see https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations)
Here is the plain JS example from the Mapbox GL website:
const el = document.createElement('div');
const width = marker.properties.iconSize[0];
const height = marker.properties.iconSize[1];
el.className = 'marker';
el.style.backgroundImage = `url(https://placekitten.com/g/${width}/${height}/)`;
el.style.width = `${width}px`;
el.style.height = `${height}px`;
el.style.backgroundSize = '100%';
el.addEventListener('click', () => {
window.alert(marker.properties.message);
});
// Add markers to the map.
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.addTo(map);
From https://docs.mapbox.com/mapbox-gl-js/example/custom-marker-icons/
One pro tip, if you have lots of images to load (like thousands of markers) you will get better performance if you have MapboxGL render it in WebGL vs using the DOM, for that see: https://docs.mapbox.com/mapbox-gl-js/example/add-image/

Vue: get image width + height returns zero on component load

My component is a modal which displays an <img> with some tags on top.
I get the image dimensions using const size = this.$refs.media.getBoundingClientRect().
However, the height and width is 0, so the tags become placed wrong.
So it seems the image hasn't loaded yet? If I delay getting the height+width with setTimeout, I do get the width and height. But it seems like a not too reliable workaround.
I have "v-cloak" on the modal, but that doesn't work.
I can get the html element with this.$refs.media, but it doesn't mean that the image is loaded, apparently.
So, is there a way to check if the image is loaded? Is there some way to delay the component until the image is loaded?
One more thing: if I add a "width" and "height" in inline style on the img, then those values are available directly. But I don't want to set the size that way because it ruins the responsiveness.
The code doesn't say much more, but it is basically:
<modal>
<vue-draggable-resizable // <-- each tag
v-for="( tag, index ) in tags"
:x="convertX(tag.position.x)"
:y="convertY(tag.position.y)"
(other parameters)
convertX (x) {
const size = this.$refs.media.getBoundingClientRect()
return x * (size.width - 100) // <--- 0 width
async mounted () {
this.renderTags(this.media.tags) // <-- needs img width and height
Updated, solution
As the below answer says, I can use the onload event. I also came across the "#load" event, which I tried and it worked. I can't find it in the documentation though(?) (I searched for #load and v-on:load). Using "onload" directly on the image element didn't work though, so #load seems to be the way.
If I have a data property:
data () {
return {
imgLoaded: false
I can set it to true with a method using #load on the image:
<img
#load="whenImgLoaded"
<template v-if="imgLoaded = true">
<vue-draggable-resizable
:x="convertX(tag.position.x)"
:y="convertY(tag.position.y)"
(other parameters)
methods: {
whenImgLoaded(){
this.imgLoaded = true;
this.renderTags(this.media.tags)
}
You could load the image first via javascript, and after it's loaded run the renderTags method.
E.g., do something like this:
async mounted() {
let image = new Image();
image.onload = function () {
this.renderTags(this.media.tags)
};
image.src = 'https://some-image.png'
}

How to use THREE js TextureLoader() in React native?

I am trying to create a 3D model in React-Native using Three.js, for that I have to use an image for texture but TextureLoader() function using 'document' and 'canvas' object creation logic, which can't be used in react-native.
so, how can I use an image as texture in react-native using three.js ?
Short summary: the Textureloader didnt work because it required an imageloader which required the inaccesible DOM.
Apparantly there's a THREE.Texture function which i used like this:
let texture = new THREE.Texture(
url //URL = a base 64 JPEG string in this case
);
var img = new Image(128, 128);
img.src = url;
texture.normal = img;
As you can see i used an Image constructor, this is from React Native and is imported like this:
import { Image } from 'react-native';
In the react native documentation it will explain how it can be used, it supports base64 encoded JPEG.
and finally map the texture to the material:
material.map = texture;
Note: i havent tried to show the end result in my webglview yet, but in the element inspector it seems to show proper THREEjs objects.
(Note: this is not the answer)
EDIT: made the code a bit shorter and use DOMParser, still doesnt work because:
"image.addEventListener is not a function"
Which implies the image object which is created in this method doesnt seem to be able to be used in THREEjs,..
var DOMParser = require('react-native-html-parser').DOMParser;
var myDomParser = new DOMParser();
window.document = {};
window.document.createElementNS = (x,y) => {
if (y === "img") {
let doc = myDomParser.parseFromString("<html><head></head><body><img class='image' src=''></img></body></html>");
return doc.getElementsByAttribute("class", "image")[0];
}
}
Edit: be careful with this, because it also overrides the other createElemensNS variants in which they create canvas or other things.

How do I create easily a PDF from an SVG with jsPDF?

I'm trying to create a pdf but I have some SVG pictures. I found information about this problem, but I just have to use JavaScript, that's to say, no jQuery.
I found jsPDF here : https://github.com/MrRio/jsPDF
There is the plugin jspdf.plugin.sillysvgrenderer.js (in the same folder) and where we can find an exemple of PDF created in the folder test.
But when I try to generate the PDF on my own, it doesn't work and I don't understand why.
Do you know how to do it?
I got this plugin working, but only with SVG file from the tests and the I saw in the doc that only PATHs are supported :(
There is already the issue on github
https://github.com/MrRio/jsPDF/issues/384
If paths are ok for here is my code (it's more or less the code from the tests):
function demoSvgDocument() {
var doc = new jsPDF();
var test = $.get('013_sillysvgrenderer.svg', function(svgText){
var svgAsText = new XMLSerializer().serializeToString(svgText.documentElement);
doc.addSVG(svgAsText, 20, 20, doc.internal.pageSize.width - 20*2)
// Save the PDF
doc.save('TestSVG.pdf');
});
}
Another point to consider, you have to run all examples on a server. Otherwise you won't see any results probably because of the security
Try canvg for that to covert SVG to Canvas. Then convert the canvas to base64 string using .toDataURL().
More detailed answer is here https://stackoverflow.com/a/35788928/2090459
Check the demo here http://jsfiddle.net/Purushoth/hvs91vpq/
Canvg Repo: https://github.com/gabelerner/canvg
There now is svg2pdf.js which uses a fork of jsPDF.
It has been created to solve this exact task: Exporting an SVG to a PDF.
Also in the meantime, jsPDF also added a demo that shows how to possibly export SVG using canvg and the jsPDF canvas implementation.
The two solutions have different advantages and disadvantages, so you might want to try both and see if one of them suits your needs.
You can use the canvas plugin that comes with jsPDF to render the SVG on the PDF with canvg. I've had to set a few dummy properties on the jsPDF canvas implementation, and disable the interactive/animation features of canvg for this to work without errors:
var jsPdfDoc = new jsPDF({
// ... options ...
});
// ... whatever ...
// hack to make the jspdf canvas work with canvg
jsPdfDoc.canvas.childNodes = {};
jsPdfDoc.context2d.canvas = jsPdfDoc.canvas;
jsPdfDoc.context2d.font = undefined;
// use the canvg render the SVG onto the
// PDF via the jsPDF canvas plugin.
canvg(jsPdfDoc.canvas, svgSource, {
ignoreMouse: true,
ignoreAnimation: true,
ignoreDimensions: true,
ignoreClear: true
});
This seems to me a much better solution than the SVG plugin for jsPDF, as canvg has much better support of SVG features. Note that the width and height properties should be set on the <svg/> element of your SVG for canvg to render it correctly (or at least so it seemed to me).
I modified this from: https://medium.com/#benjamin.black/using-blob-from-svg-text-as-image-source-2a8947af7a8e
var yourSVG = document.getElementsByTagName('svg')[0];
//or use document.getElementById('yourSvgId'); etc.
yourSVG.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/2000/svg');
yourSVG.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink');
var serializer = new XMLSerializer();
var serialSVG = serializer.serializeToString(yourSVG);
var svg = serialSVG;
var blob = new Blob([svg], {type: 'image/svg+xml'});
var url = URL.createObjectURL(blob);
var image = document.createElement('img');
// image.addEventListener('load', () => URL.revokeObjectURL(url), {once: true});
//changed above line using babel to code below;
image.addEventListener('load', function () {
return URL.revokeObjectURL(url);
}, { once: true });
image.src = url;
//Then just use your pdf.addImage() function as usual;