Ionic 3 - remove images from an ion-slides with help of .getActiveIndex() - javascript

I have added images from gallery/camera to an ion-slider view.I have an action sheet which gives me an option to add or remove the images from the slider view.Adding is working fine as i am adding that image to array and providing that updated array to the slider.
But for removing an image i need to get the index of the image that is active on the slider and after that i need to remove it.
I m not able to get the active index using this code :
onSlideChanged() {
try{
let currentIndex = this.slides.getActiveIndex();
console.log("Current index is", currentIndex);
}catch(e){
console.log("not able to get the active index");
} }
this also goes into the catch part.
Then i m removing the first element from the array and updating the array for slider.The array size is reduced when i press the delete button from action sheet but all the images in the slider disappears leaving a blank space.
<div *ngIf="field.value" (click)="takePicture(field.name)">
<ion-slides pager="true" style="max-height:500px" (ionSlideDidChange)="onSlideChanged()">
<ion-slide *ngFor="let c of field.value">
<img class="image-attach" [src]="c" draggable="true">
</ion-slide>
</ion-slides>
</div>
<canvas #latlon style="display:none"></canvas>
</div>
code for setting images to the slider
removePicture(name) {
for (let i = 0; i < this.formType.template.secs.length; i++) {
for (let d = 0; d < this.formType.template.secs[i].fields.length; d++) {
if (this.formType.template.secs[i].fields[d].name == name) {
if(this.formType.template.secs[i].fields[d].value.length>1)
{
this.formType.template.secs[i].fields[d].value.splice(this.currentIndex,1);
this.attachedImagesArray.splice(this.currentIndex,1);
console.log(this.formType.template.secs[i].fields[d].value.length);
var arr = this.formType.template.secs[i].fields[d].value;
console.log("^^^^^^^",arr);
this.formType.template.secs[i].fields[d].value = this.formType.template.secs[i].fields[d].value;
}
else{
console.log("*********",this.formType.template.secs[i].fields[d].value);
this.formType.template.secs[i].fields[d].value = "";
}
}
}
}
};
this is the code i m using for removing the images from slider.
I m new to ionic so don't know why this is happening, i googled for it but nothing worked for me.
for putting the images to the slides i m using the following code :
selecPicture(name) {
this.camera.getPicture({
quality: 50,
destinationType: this.camera.DestinationType.FILE_URI,
targetHeight: 500,
targetWidth: 500,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
sourceType: this.camera.PictureSourceType.PHOTOLIBRARY
}).then((imageData) => {
//alert(imageData);
// imageData is a base64 encoded string DATA_URL FILE_URI 'lat: '+lat+', lon: '+lon,
let base64Image = "data:image/jpeg;base64," + imageData;
this.geolocation.getCurrentPosition().then((resp) => {
let lat = resp.coords.latitude;
let lon = resp.coords.longitude;
this.lat = lat;
this.lon = lon;
let d = new Date();
let draftSavedTime = d.toString().substr(4, 11);
let canvas = this.canvasRef.nativeElement;
let context = canvas.getContext('2d');
console.log(context);
console.log("hello");
let newImg = new Image();
newImg.src = imageData;
newImg.onload = () => {
canvas.setAttribute("width", newImg.height);
canvas.setAttribute("height", newImg.width);
// context.drawImage(newImg, 0, 0);
context.drawImage(newImg, 0, 0, newImg.width, newImg.height);
// context.font = "15px impact";
context.font = "bold 13px Arial";
// context.textAlign = 'center';
context.fillStyle = 'red';
context.fillText(draftSavedTime, 20, 20);
// context.fillText('Lat: '+lat+' Lon: '+lon, canvas.width / 2, canvas.height * 0.9);
context.fillText('Lat: ' + lat, canvas.width * 0.1, canvas.height * 0.8);
context.fillText('Lon: ' + lon, canvas.width * 0.1, canvas.height * 0.9);
// context.fillText('Lon: '+lon, canvas.width / 2, canvas.height * 0.8);
let image = canvas.toDataURL();
this.attachedImages.push(image);
this.setValue(name, image);
};
}).catch((error) => {
console.log('Error getting location', error);
});
}, (err) => {
console.log(err);
});
}
to set the value of image in the field :
//to set the value in the field
setValue(name, data) {
console.log(this.attachedImages);
console.log(this.formType.template.secs); //3
for (let i = 0; i < this.formType.template.secs.length; i++) {
console.log(this.formType.template.secs[i].fields); //2
for (let d = 0; d < this.formType.template.secs[i].fields.length; d++) {
if (this.formType.template.secs[i].fields[d].name == name) {
this.attachedImagesArray.push({
name : this.formType.template.secs[i].fields[d].name,
image : data,
number : d
});
var group_to_values = this.attachedImagesArray.reduce(function (obj, item) {
obj[item.name] = obj[item.name] || [];
obj[item.name].push(item.image);
return obj;
}, {});
var imageGroup = Object.keys(group_to_values).map(function (key) {
return {key: key, image: group_to_values[key]};
});
var pre = document.createElement("pre");
pre.innerHTML = "imageGroup:\n\n" + JSON.stringify(imageGroup, null, 4);
document.body.appendChild(pre);
var newArr = [];
newArr.push({imageGroup});
for(var item in newArr)
{
console.log(newArr[item]);
for(var sec in newArr[item])
{
console.log(newArr[item][sec]);
}
for( var elm in newArr[item][sec])
{
console.log(newArr[item][sec][elm]);
}
for( var key in newArr[item][sec][elm])
{
this.arrNameStr = newArr[item][sec][elm].key;
console.log(newArr[item][sec][elm].image);
}
}
console.log(this.arrNameStr);
if(this.arrNameStr.includes(this.formType.template.secs[i].fields[d].name))
{
console.log(newArr[item][sec][elm].image);
console.log(this.formType.template.secs[i].fields[d].value);
this.formType.template.secs[i].fields[d].value = newArr[item][sec][elm].image;
console.log(this.formType.template.secs[i].fields[d].value);
}
}
}
}
};

First ensure that you get this event firing off and that your reference to the slides element in the template returns the Slides: (ionSlideDidChange). Do:
onSlideChanged() {
console.log(this.slides)
}
Your console should return reference to the slides element.
It is unclear how you obtain this reference based on your code, but seeing you have *ngIf directive there is a chance you are not actually able to get it since the element doesn't exist at init stage of the component.
To fix that you can pass reference to ion-slides in the ionSlidesChanged method:
<div *ngIf="field.value" (click)="takePicture(field.name)">
<ion-slides #mySlides (ionSlideDidChange)="onSlideChanged(mySlides); mySlides.update()" pager="true" style="max-height:500px">
<ion-slide *ngFor="let c of field.value">
<img class="image-attach" [src]="c" draggable="true">
</ion-slide>
</ion-slides>
</div>
Now in the actual method you should be able to get the value of currentIndex:
onSlideChanged(mySlides) {
let currentIndex = mySlides..getActiveIndex();
// here do splice or whatever manipulation you need with your data source / array
}
Let me know if this helped.
UPDATE: since there is a need to refresh slides UI after the change to the model it is good to call "update" method: (ionSlideDidChange)="onSlideChanged(mySlides); mySlides.update()".
Template is now updated with this.

Related

How to download pdf in nuxt project?

<div style="height: 0;position: fixed; left: 50%; top: 0; transform: translateX(-50%);
z-index: -1;overflow: hidden">
<ticket-pdf v-if="pdfData" :pdfData="pdfData" :downloadBtn="downloadBtn" #download="downloadBtn = $event" /> </div>
In my nuxt project, i need to download pdf file in my main componet .When user clicked download button it will be downloaded directlty without previewing pdf component. So i hide my ticket-pdf component inside my main component . This way works in localhost but when i published my project to test area it does not work. It download only 1 empty page. and i face with this mistake.
Failed to load resource: the server responded with a status of 500 ()
If i open my pdf file in a other page and i can preview and download it also. But i need to doownload it without routing anywhere and directly in my main component
printPDF() {
const html2canvasOptions = {
allowTaint: true,
removeContainer: true,
imageTimeout: 15000,
logging: true,
useCORS: true,
scrollX: 0,
scrollY: 0,
scale: 2,
};
// Initialize the PDF.
let pdf = new jsPDF('p', 'in', [8.5, 11], false);
let totalPage = 0
//i have many pages and countof pages changes . It depends. so firstly i calculate page count and create pdf.
let pageCount = document.querySelectorAll('[id^=contentPrint]').length
for (let i = 0; i < pageCount; i++) {
const contentPrint = document.getElementById('contentPrint-' + i);
html2canvas(contentPrint, html2canvasOptions)
.then((canvas) => {
const image = {type: 'jpeg', quality: 1};
const margin = [0.5, 0.5];
let imgWidth = 8.5;
let pageHeight = 11;
let innerPageWidth = imgWidth - margin[0] * 2;
let innerPageHeight = pageHeight - margin[1] * 2;
// Calculate the number of pages.
let pxFullHeight = canvas.height;
let pxPageHeight = Math.floor(canvas.width * (pageHeight / imgWidth));
let nPages = Math.ceil(pxFullHeight / pxPageHeight);
totalPage += nPages
// Define pageHeight separately so it can be trimmed on the final page.
pageHeight = innerPageHeight;
// Create a one-page canvas to split up the full image.
let pageCanvas = document.createElement('canvas');
let pageCtx = pageCanvas.getContext('2d');
pageCanvas.width = canvas.width;
pageCanvas.height = pxPageHeight;
for (let page = 0; page <= nPages; page++) {
// Trim the final page to reduce file size.
if (page === nPages - 1 && pxFullHeight % pxPageHeight !== 0) {
pageCanvas.height = pxFullHeight % pxPageHeight;
pageHeight = (pageCanvas.height * innerPageWidth) / pageCanvas.width;
}
// Display the page.
let w = pageCanvas.width;
let h = pageCanvas.height;
pageCtx.fillStyle = 'white';
pageCtx.fillRect(0, 0, w, h);
pageCtx.drawImage(canvas, 0, page * pxPageHeight, w, h, 0, 0, w, h);
// Add the page to the PDF.
if (page > 0) pdf.addPage();
let imgData = pageCanvas.toDataURL('image/' + image.type, image.quality);
pdf.addImage(imgData, image.type, margin[1], margin[0], innerPageWidth, pageHeight);
}
});
}
setTimeout(() => {
// pdf.deletePage(totalPage + 1)
pdf.save("e-ticket" + '.pdf')
}, 3000)
setTimeout(() => {
this.$emit("download", this.download);
}, 4000)
},
This is how i create pdf area. When user clicked download button i create pdf and download it thanks to my props.
printPDF() {
window.scrollTo(0, 0);
// Initialize the PDF.
let pdf = new jsPDF('p', 'in', [8.5, 11], false);
let totalPage = 0
let counter = 0
let myArray = []
let pageCount = document.querySelectorAll('[id^=contentPrint]').length
for (let i = 0; i < pageCount; i++) {
myArray.push('contentPrint-' + i)
}
for (let i = 0; i < pageCount; i++) {
const contentPrint = document.getElementById('contentPrint-' + i);
html2canvas(contentPrint, {
scale: 2, useCORS: true, allowTaint: true, scrollY: 0
}).then((canvas) => {
.................
........
.....
counter = counter + 1;
callBack();
})
}
const callBack = () => {
if (myArray.length === counter) {
pdf.save("filename" + '.pdf')
this.$emit("download", this.download);
}
}
},
the problem was about my settimeout function . ın there ı would call pdf.save before pdf created and sure every browser works in different speed. so if we use callback function after all process done , then we can obtain our pdf rpint
You could maybe try to simply put
<a href="/your_file.csv" download>
by putting your_file.csv into the static directory.
Not sure if it can be enough in your case, sorry if it's not.

How to integrate WebGL into existing game which is using canvas and 2D context.drawImage?

I have a game which uses context.drawImage() to draw spritesheets of the game objects into a hidden canvas which is then copied over to another canvas(viewport). The current renderer has a camera which copies a portion of the canvas to the view. Each gameobject is added to a layer in the renderer and sorted by some value x each frame before rendering. Layers are drawn in a specific order and objects in the layers aswell.
So I have following structure:
//Renderer object
var layers = [[object,object,object,object],//objects sorted according to when they should be rendered
[object,object,object,object],
[object,object,object]];
//Simplified one frame render function
for(var i = 0; i < layers.length;i++){
for(var j = 0; j < layers[i].length;j++){
this.drawImage(layers[i][j]);
}
}
...
//DrawImage function
this.drawImage = function(object){
if(typeof object.currentAnimation !== "undefined"){//draw animation
var tileId = object.currentAnimation.tileIds[object.currentAnimation.currentTile];
var amountOfBlocksInARow = object.currentAnimation.tilesheet.width/object.currentAnimation.tileSize;
var sourceX = Math.floor(tileId % amountOfBlocksInARow) *object.currentAnimation.tileSize;
var sourceY = Math.floor(tileId / amountOfBlocksInARow) *object.currentAnimation.tileSize;
this.canvasContext.drawImage(object.currentAnimation.tilesheet, sourceX, sourceY, object.currentAnimation.tileSize, object.currentAnimation.tileSize, object.x, object.y,object.width,object.height);
object.currentAnimation.nextFrame();
}else{//if theres no animation just an image then draw with object properties}
}
...
//Rest of the render function
//snap camera to its target then copy the camera to the view
this.cameraSnapToTarget();
this.viewportContext.drawImage(this.canvas, this.camera.x, this.camera.y, this.camera.width, this.camera.height, 0, 0, this.viewportCanvas.width, this.viewportCanvas.height);
And this html: <canvas id="hiddenCanvas"></canvas> <canvas id="viewportCanvas"></canvas>
I was wondering if there was a way to implement the WebGL into this so I wouldn't have to change the structure. Currently I have tried to initialize webgl, make some buffers and shaders, but I can't seem to draw anything with it. I followed https://webglfundamentals.org/webgl/lessons/webgl-2d-drawimage.html this and don't know how to set up the buffers and shaders to benefit from the original code.
Do I have to change this structure or can it be implemented in this?
Thank you in advance for any help!
There was a few things I needed to add for my code for this to work
First I needed to make textures of the spritesheets I use for the gameobjects:
//I load all my images into an array I can search from
var imageArray = [];//global variables
var textures = [];//global variables
//and use it after defining onload like this:
imageArray.push(img);
After images have all loaded I initialize the textures for the webgl:
for(var i = 0; i < imageArray.length; i++){
initializeTexture(imageArray[i]);
}
function initializeTexture(img){//these images are already loaded into the dom
var tex = renderer.viewportContext.createTexture();
renderer.viewportContext.bindTexture(renderer.viewportContext.TEXTURE_2D, tex);
renderer.viewportContext.texParameteri(renderer.viewportContext.TEXTURE_2D, renderer.viewportContext.TEXTURE_WRAP_S, renderer.viewportContext.CLAMP_TO_EDGE);
renderer.viewportContext.texParameteri(renderer.viewportContext.TEXTURE_2D, renderer.viewportContext.TEXTURE_WRAP_T, renderer.viewportContext.CLAMP_TO_EDGE);
renderer.viewportContext.texParameteri(renderer.viewportContext.TEXTURE_2D, renderer.viewportContext.TEXTURE_MIN_FILTER, renderer.viewportContext.LINEAR);
var texture = {
width: img.width,
height: img.height,
texture: tex,
};
renderer.viewportContext.bindTexture(renderer.viewportContext.TEXTURE_2D, tex);
renderer.viewportContext.texImage2D(renderer.viewportContext.TEXTURE_2D, 0, renderer.viewportContext.RGBA, renderer.viewportContext.RGBA, renderer.viewportContext.UNSIGNED_BYTE, img);
textures.push(texture);//array containing one of each spritesheet texture
}
Then I have Animation object which I use to assign spritesheets to gameobjects:
function Animation(spritesheet,tileSize,tileIds,name = "",playOnce = false){
this.name = name;
this.spritesheet = spritesheet;
this.tileSize = tileSize;
this.tileIds = tileIds;
this.speed = 1;
this.currentTile = 0;
this.playOnce = playOnce;
this.texture;
this.state = "stopped";
this.setAnimationSpeed = function(speed){
this.speed = speed;
}
this.setTextureFromImage = function(img){
this.texture = textures[imageArray.indexOf(img)];//find the spritesheet from array of images which is indexed same as textures array texture[i] = imageArray[i] etc.
}
this.setName = function(name){
this.name = name;
}
this.setLoop = function (loop){
this.loop = loop;
}
this.setSpritesheet = function (spritesheet){
this.spritesheet = spritesheet;
}
this.setState = function(state){
this.state = state;
}
this.getState = function(){
return this.state;
}
this.play = function(){
this.state = "playing";
}
this.stop = function(){
this.state = "stopped";
}
this.nextFrame = function(){
if(this.state == "playing"){
if(typeof this.tileIds[this.currentTile+1] !== "undefined"){
this.currentTile++;
}else{
if(this.playOnce)
this.setState("played");
else
this.currentTile = 0;
}
}
}
this.setTextureFromImage(this.spritesheet);
}
As optimization I could use the index of imageArray and get the texture from the original texture array when rendering.
I use the Animation object in all gameobjects like this:
this.animations = [
new Animation(this.spritesheet,32,[0,1],"walkDown"),//walkdown
new Animation(this.spritesheet,32,[2,3],"walkRight"),//walkright
new Animation(this.spritesheet,32,[4,5],"walkLeft"),//walkleft
new Animation(this.spritesheet,32,[6,7],"walkUp"),//walkup
]
Finally I can render them with:
//Renderer
this.viewportContext = this.viewportCanvas.getContext("webgl",{ alpha: false ,premultipliedAlpha: false});
this.render = function(){//render one frame
this.sortLayers();//can do sorting here
this.viewportContext.viewport(0,0,this.viewportContext.canvas.width,
this.viewportContext.canvas.height);
this.viewportContext.clear(this.viewportContext.COLOR_BUFFER_BIT);//clear buffers before rendering
for(var i = 0; i < this.layerArray.length;i++){
if(this.layerArray[i].constructor === Array){
for(var j = 0; j < this.layerArray[i].length;j++){
var object = this.layerArray[i][j];
if(typeof object.currentAnimation !== "undefined"){
var tileId = object.currentAnimation.tileIds[object.currentAnimation.currentTile];
var amountOfBlocksInARow = object.currentAnimation.spritesheet.width/object.currentAnimation.tileSize;
var sourceX = Math.floor(tileId % amountOfBlocksInARow) *object.currentAnimation.tileSize;
var sourceY = Math.floor(tileId / amountOfBlocksInARow) *object.currentAnimation.tileSize;
this.drawImage(object.currentAnimation.texture.texture,
object.currentAnimation.texture.width,
object.currentAnimation.texture.height,
sourceX, sourceY,
object.currentAnimation.tileSize,
object.currentAnimation.tileSize,
object.x,object.y,
object.width,object.height);
}
}
}
}
}
}
this.drawImage = function(tex, texWidth, texHeight,srcX, srcY, srcWidth, srcHeight,dstX, dstY, dstWidth, dstHeight){
if (dstX === undefined) {
dstX = srcX;
srcX = 0;
}
if (dstY === undefined) {
dstY = srcY;
srcY = 0;
}
if (srcWidth === undefined) {
srcWidth = texWidth;
}
if (srcHeight === undefined) {
srcHeight = texHeight;
}
if (dstWidth === undefined) {
dstWidth = srcWidth;
srcWidth = texWidth;
}
if (dstHeight === undefined) {
dstHeight = srcHeight;
srcHeight = texHeight;
}
this.viewportContext.enable(this.viewportContext.BLEND);
this.viewportContext.blendFunc(this.viewportContext.SRC_ALPHA, this.viewportContext.ONE_MINUS_SRC_ALPHA);
this.viewportContext.bindTexture(this.viewportContext.TEXTURE_2D, tex);
this.viewportContext.useProgram(program);
this.viewportContext.bindBuffer(this.viewportContext.ARRAY_BUFFER,positionBuffer);
this.viewportContext.enableVertexAttribArray(positionAttributeLocation);
this.viewportContext.vertexAttribPointer(positionAttributeLocation, 2, this.viewportContext.FLOAT, false, 0, 0);
this.viewportContext.bindBuffer(this.viewportContext.ARRAY_BUFFER, textureCoordinateBuffer);
this.viewportContext.enableVertexAttribArray(textureCoordinateLocation);
this.viewportContext.vertexAttribPointer(textureCoordinateLocation, 2, this.viewportContext.FLOAT, false, 0, 0);
this.matrix = m4.orthographic(0, this.viewportContext.canvas.width, this.viewportContext.canvas.height, 0, -1, 1);
this.matrix = m4.translate(this.matrix,dstX,dstY,0);
this.matrix = m4.scale(this.matrix, dstWidth, dstHeight, 1);
this.viewportContext.uniformMatrix4fv(matrixLocation,false,this.matrix);
var textureMatrix = m4.scaling(1/ texWidth, 1/texHeight, 1);
//scaling
textureMatrix = m4.translate(textureMatrix, srcX, srcY, 0);
textureMatrix = m4.scale(textureMatrix, srcWidth, srcHeight, 1);
this.viewportContext.uniformMatrix4fv(textureMatrixLocation, false, textureMatrix);
this.viewportContext.drawArrays(this.viewportContext.TRIANGLES, 0, 6);
}

Firefox extension not able to select all images may be due to Canvas fuction getImageData()

In the below code I have imported my machine learning model through function model_startup(). model_startup() is working fine. But after that, I am getting into function blockk(), through this function I am trying to select all images on website by document.getElementsByTagName('img') and do prediction through that image with the help of an imported model. But my problem is that my second function is not selecting all images on website and selecting only some number of starting images and after prediction on that some number of images it get stopped.
I am new to javascript and trying to implement it as a firefox extension. Please help me in this problem
console.log('STARTING UP')
const MODEL_PATH = 'mdl/model.json'
const IMAGE_SIZE = 64;
let model;
async function model_startup()
{
console.log('Launching TF.js!');
tf.ENV.set('WEBGL_PACK',false);
await tf.ready();
console.log('TensorflowJS backend is: '+tf.getBackend());
let url = browser.runtime.getURL(MODEL_PATH);
console.log('Loading model... '+url);
try
{
model = await tf.loadLayersModel(url);
}
catch(e)
{
console.log('Failed to load model! '+e);
}
console.log('Model: ' + model);
console.log('Warming up...');
let dummy_data = tf.zeros([1, IMAGE_SIZE, IMAGE_SIZE, 3]);
// dummy_data.print();
let warmup_result = model.predict(dummy_data);
console.log("finding type : $$$$$$$$ " + typeof warmup_result)
warmup_result.print();
warmup_result.dispose();
console.log('Ready to go!');
// blockk();
};
model_startup().then(blockk);
function blockk() {
const x = document.getElementsByTagName('img');
console.log("wn ############################## " + x.length);
let inferenceCanvas = document.createElement('canvas');
inferenceCanvas.width = 64;
inferenceCanvas.height = 64;
let inferenceCtx = inferenceCanvas.getContext('2d', { alpha: false});
inferenceCtx.imageSmoothingEnabled = true;
for(var i = 0; i < x.length; i++)
{
console.log('pixel kmvsl lsvn');
let img = x[i];
inferenceCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, 64, 64);
const rightSizeImageData = inferenceCtx.getImageData(0, 0, 64, 64); //write promise. It may work.
const rightSizeImageDataTF = tf.browser.fromPixels(rightSizeImageData);
const floatImg = rightSizeImageDataTF.toFloat();
console.log('predicting...');
let scaled = floatImg.div(tf.scalar(255));
let batched = tf.stack([scaled]);
let result = model.predict(batched);
const val = result.dataSync()[0];
console.log(val);
if (val > 0.4)
{
console.log("blocking" + i);
let h = img.height
let w = img.width
pth = img.src
x[i].setAttribute("src", "https://indianonlineseller.com/wp-content/uploads/2017/05/blocked-listing.png");
// x[i].setAttribute("onclick", ` this.src = '${pth}' `);
x[i].setAttribute("data-src", "https://indianonlineseller.com/wp-content/uploads/2017/05/blocked-listing.png");
x[i].height = h;
x[i].width = w;
console.log('blocked');
}
console.log("co ########################### " + x.length)
}
};
The line in my code which is causing problem is
const rightSizeImageData = inferenceCtx.getImageData(0, 0, 64, 64);
If I remove this code and other code related to this line and I run it then my code is able to select all the images on webpage. Can you tell me why this may be happening?

How to detect, that drawing a canvas object is finished?

I have following JS code (found here, on stackoverflow, and a little-bit modded), which resize image on client side using canvas.
function FileListItem(a) {
// Necesary to proper-work of CatchFile function (especially image-resizing).
// Code by Jimmy Wärting (https://github.com/jimmywarting)
a = [].slice.call(Array.isArray(a) ? a : arguments)
for (var c, b = c = a.length, d = !0; b-- && d;) d = a[b] instanceof File
if (!d) throw new TypeError('expected argument to FileList is File or array of File objects')
for (b = (new ClipboardEvent('')).clipboardData || new DataTransfer; c--;) b.items.add(a[c])
return b.files
}
function CatchFile(obj) {
// Based on ResizeImage function.
// Original code by Jimmy Wärting (https://github.com/jimmywarting)
var file = obj.files[0];
// Check that file is image (regex)
var imageReg = /[\/.](gif|jpg|jpeg|tiff|png|bmp)$/i;
if (!file) return
var uploadButtonsDiv = document.getElementById('upload_buttons_area');
// Check, that it is first uploaded file, or not
// If first, draw a div for showing status
var uploadStatusDiv = document.getElementById('upload_status_area');
if (!uploadStatusDiv) {
var uploadStatusDiv = document.createElement('div');
uploadStatusDiv.setAttribute('class', 'upload-status-area');
uploadStatusDiv.setAttribute('id', 'upload_status_area');
uploadButtonsDiv.parentNode.insertBefore(uploadStatusDiv, uploadButtonsDiv.nextSibling);
// Draw sub-div for each input field
var i;
for (i = 0; i < 3; i++) {
var uploadStatus = document.createElement('div');
uploadStatus.setAttribute('class', 'upload-status');
uploadStatus.setAttribute('id', ('upload_status_id_commentfile_set-' + i + '-file'));
uploadStatusDiv.append(uploadStatus);
}
}
var canvasDiv = document.getElementById('canvas-area');
var currField = document.getElementById(obj.id);
var currFieldLabel = document.getElementById(('label_' + obj.id));
// Main image-converting procedure
if (imageReg.test(file.name)) {
file.image().then(img => {
const canvas = document.createElement('canvas')
canvas.setAttribute('id', ('canvas_' + obj.id));
const ctx = canvas.getContext('2d')
const maxWidth = 1600
const maxHeight = 1200
// Calculate new size
const ratio = Math.min(maxWidth / img.width, maxHeight / img.height)
const width = img.width * ratio + .5|0
const height = img.height * ratio + .5|0
// Resize the canvas to the new dimensions
canvas.width = width
canvas.height = height
// Drawing canvas-object is necessary to proper-work
// on mobile browsers.
// In this case, canvas is inserted to hidden div (display: none)
ctx.drawImage(img, 0, 0, width, height)
canvasDiv.appendChild(canvas)
// Get the binary (aka blob)
canvas.toBlob(blob => {
const resizedFile = new File([blob], file.name, file)
const fileList = new FileListItem(resizedFile)
// Temporary remove event listener since
// assigning a new filelist to the input
// will trigger a new change event...
obj.onchange = null
obj.files = fileList
obj.onchange = CatchFile
}, 'image/jpeg', 0.70)
}
)
// If file is image, during conversion show status
function ShowConvertConfirmation() {
if (document.getElementById('canvas_' + obj.id)) {
document.getElementById(('upload_status_' + obj.id)).innerHTML =
'<font color="#4CAF50">Konwertowanie pliku ' + file.name + ' zakończone!</font>';
return true;
}
else {
document.getElementById(('upload_status_' + obj.id)).innerHTML =
'<font color="#4CAF50">Konwertowanie pliku ' + file.name + ' zakończone!</font>';
return false;
}
}
// Loop ShowConvertConfirmation function untill return true (file is converted)
var convertConfirmationLoop = setInterval(function() {
var isConfirmed = ShowConvertConfirmation();
if (!isConfirmed) {
ShowConvertConfirmation();
}
else {
// Break loop
clearInterval(convertConfirmationLoop);
}
}, 2000); // Check every 2000ms
}
// If file is not an image, show status with filename
else {
document.getElementById(('upload_status_' + obj.id)).innerHTML =
'<font color="#4CAF50">Dodano plik ' + file.name + '</font>';
//uploadStatusDiv.append(uploadStatus);
}
}
Canvas is drawn in hidden div:
<div id="canvas-area" style="overflow: hidden; height: 0;"></div>
I am only detect, that div canvas-area is presented and basing on this, JS append another div with status.
Unfortunatelly on some mobile devices (mid-range smartphones), message will be showed before finish of drawing (it is wrong). Due to this, some uploaded images are corrupted or stay in original size.
How to prevent this?
Everything that should happen after the image has loaded, should be executed within the then callback, or called from within it.
It is important to realise that the code that is not within that callback will execute immediately, well before the drawing has completed.

Maximum call stack size exceeded in custom Image filter

I am looking for a way to fill an Image with an image pattern in a FabricJs canvas, since there is not a built-in image filter to do this. Although my code is still in an early version, basically it should work(unfortunately it doesn't);
All the eavy work is done by applyTo method, where I load an image, then fill an hidden canvas with a pattern. I noticed that there is a function (source) which fall in an infinite recursion:
var pattern = new fabric.Pattern({
source: function () {
fhc.setDimensions({
width: smile.getWidth() + 5,
height: smile.getHeight() + 5,
});
return fhc.getElement();
},
repeat: 'repeat'
});
I have prepared a demo on JSFiddle
Could anyone help me to understand how to solve this issue?
(function (global) {
'use strict';
var fabric = global.fabric || (global.fabric = {}),
extend = fabric.util.object.extend;
fabric.Image.filters.ImagePatternEffect = fabric.util.createClass(fabric.Image.filters.BaseFilter, {
type: 'ImagePatternEffect',
initialize: function (options) {
options = options || {};
this.img = options.img;
},
applyTo: function (canvasEl) {
var w = canvasEl.width;
var h = canvasEl.height;
var hc = document.createElement('canvas');
fabric.Image.fromURL('http://i.imgur.com/0Ks0mlY.png', function (smile) {
debugger;
hc.setAttribute('width', w);
hc.setAttribute('height', h);
var fhc = new fabric.StaticCanvas(hc);
fhc.add(smile);
var pattern = new fabric.Pattern({
source: function () {
fhc.setDimensions({
width: smile.getWidth() + 5,
height: smile.getHeight() + 5,
});
return fhc.getElement();
},
repeat: 'repeat'
});
var rect = new fabric.Rect({
fill: pattern,
width: w,
height: h
});
fhc.add(rect);
fhc.renderAll();
var ifhcContext = fhc.getContext('2d');
var fhcImageData = ifhcContext.getImageData(0, 0, fhc.width, fhc.height);
var fhcData = fhcImageData.data;
var context = canvasEl.getContext('2d'),
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
data = imageData.data;
for (var i = 0, n = data.length; i < n; i += 4) {
data[i] += fhcData[i];
data[i + 1] += fhcData[i + 1];
data[i + 2] += fhcData[i + 2];
}
context.putImageData(imageData, 0, 0);
});
},
toObject: function () {
return extend(this.callSuper('toObject'), {
});
}
});
fabric.Image.filters.ImagePatternEffect.fromObject = function (object) {
return new fabric.Image.filters.ImagePatternEffect(object);
};
})(typeof exports !== 'undefined' ? exports : this);
var canvas = new fabric.Canvas('c');
fabric.Image.fromURL('http://i.imgur.com/qaQ8jir.png', function (img) {
var orImg = img;
img.filters.push(new fabric.Image.filters.ImagePatternEffect({
img: orImg,
}));
img.applyFilters(canvas.renderAll.bind(canvas));
canvas.add(img.set({
width: 300,
height: 300,
}));
}, {
crossOrigin: ''
});
i also use pattern image on my web application , in order to add it on objects, and it works.
All you need is this function function loadPattern(url, seatObj) where i pass the object which i want to add the pattern each time and the image(pattern) link.
here is the snippet :
function loadPattern(url, seatObj) {
//i use the loadImage function to load the image and pass it to the fabric.Pattern constructor
fabric.util.loadImage(url, function (img) {
//i change the fill property of the object to the
//image that i want to load on it as a pattern
seatObj.fill = new fabric.Pattern({
source: img,
repeat: 'no-repeat'
});
//refresh canvas and watch your image pattern on the object
canvas.renderAll();
});
}
hope this helps,
good luck

Categories

Resources