removeAllChildren is not working in createjs - html5-canvas

I'm trying to change the bitmap image in createjs and want to remove all children in a container when reset button is clicked. But removeAllChildren is not working in me.
function drawPhoneImage() {
stage = new createjs.Stage('canvas');
container = new createjs.Container();
phone = new createjs.Bitmap(phoneImg);
phone.x = 268;
phone.y = 64;
stage.addChild(container);
container.addChild(phone);
stage.update();
phone.addEventListener("click", function() {
console.log('phone clicked');
createjs.Ticker.addEventListener("tick", movePhoneImage);
});
}
function movePhoneImage(event) {
phone.x -=10;
if(phone.x < 156) {
phone.x =156;
showPhoneSnap();
}
stage.update(event);
}
Then after clicking the phone object, I'll need to replace it with another bitmap(which works):
function showPhoneSnap() {
snap = new createjs.Bitmap(snapImg);
snap.x = 156;
snap.y = 64;
container.removeAllChildren();
container.addChild(snap);
stage.update();
}
At first, removeAllChildren is working in the first child of the container, but when i tried resetting the stage after adding another bitmap in the container..removeAllChildren() is not working.
function resetStage() {
container.removeAllChildren();
stage.update();
}
I'm having a hard time solving this issue, thanks for anyone who can help.

Make sure that "snapImg" is an image that is loaded.
snap = new createjs.Bitmap(snapImg);
The issue is that you are not updating the stage when the image is loaded.
var image = new Image();
image.src = "path";
image.onload = showPhoneSnap;
function showPhoneSnap() {
//This will ensure that the image is ready.
var bmp = new createjs.Bitmap(this);
...
stage.update();
}

Related

ZXing.Mobile - How to change the size of the camera scanner?

UPDATE:
I've tried implementing this in an App.cs method called OpenCameraScanner (you would call this on click of a button on the page from which you want to scan):
App.cs
------------------------------------------------
public static ZXingScannerPage ScanPage;
public static ZXing.Result ScanResult;
public static async void OpenCameraScanner()
{
ScanPage = new ZXingScannerPage(customOverlay: customOverlay);
ScanPage.OnScanResult += (result) =>
{
ScanPage.IsScanning = false;
ScanResult = result;
Device.BeginInvokeOnMainThread(() =>
{
App.CurrentApp.CurrentPage.Navigation.PopModalAsync();
App.CurrentApp.CurrentPage.DisplayAlert("Scanned Barcode", result.Text, "OK");
});
};
var scanPage = new NavigationPage(ScanPage);
await App.CurrentApp.CurrentPage.Navigation.PushModalAsync(ScanPage);
}
However, when this method is called, the screen that opens is blank white, and you can't see the camera view behind it. Not sure why?
I'm using ZXing.Mobile in a Xamarin.Forms project (for iOS right now) for camera scanning functionality on an iPad.
Currently, I have it working great with the following 2 lines:
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var result = await scanner.Scan();
However, when the camera is open to scan, it takes up the entire iPad screen, which is really big.
Question: Is there a way to adjust the size of the camera overlay? (so that it's not full screen)
I see that the scanner.Scan() method takes an optional options parameter of type ZXing.Mobile.MobileBarcodeScanningOptions - I tried playing around with that, but the only possible relevant option there is a CameraResolutionSelector - but I'm having a really hard time finding any documentation on that.
There is a ZXing sample app that shows how to embed the ZXingScannerView and ZXingDefaultOverlay into a Xamarin.Form's Grid:
https://github.com/Redth/ZXing.Net.Mobile/blob/master/Samples/Forms/Core/CustomScanPage.cs
public CustomScanPage () : base ()
{
zxing = new ZXingScannerView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
AutomationId = "zxingScannerView",
};
zxing.OnScanResult += (result) =>
Device.BeginInvokeOnMainThread (async () => {
// Stop analysis until we navigate away so we don't keep reading barcodes
zxing.IsAnalyzing = false;
// Show an alert
await DisplayAlert ("Scanned Barcode", result.Text, "OK");
// Navigate away
await Navigation.PopAsync ();
});
overlay = new ZXingDefaultOverlay
{
TopText = "Hold your phone up to the barcode",
BottomText = "Scanning will happen automatically",
ShowFlashButton = zxing.HasTorch,
AutomationId = "zxingDefaultOverlay",
};
overlay.FlashButtonClicked += (sender, e) => {
zxing.IsTorchOn = !zxing.IsTorchOn;
};
var grid = new Grid
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
};
grid.Children.Add(zxing);
grid.Children.Add(overlay);
// The root page of your application
Content = grid;
}

Why does live camera capture control with Xamarin Forms on iOS freeze?

I downloaded the source for Xamarin Moments from GitHub and now I'm trying to convert the CameraPage renderer from Page to a ContentView
Then I refactored the code to make it a ContentView renderer. Most of the actual setup of the live preview and image capture comes from the Moments app with some refactoring where needed/preferred.
The live preview shows up but when I press the button to take the picture the app freezes without an exception, not even in Xcode's console view.
//this is how it's called:
btnTakePicture.Clicked += (s,e)=> { GetCameraImage().Wait(); };
// this method freezes
public async Task<byte[]> GetCameraImage()
{
byte[] imageBuffer = null;
if (captureDeviceInput != null)
{
var videoConnection = stillImageOutput.ConnectionFromMediaType(AVMediaType.Video);
Console.WriteLine("[HASFIQWRPPOA] This message shows up");
// this is where the app freezes, even though the live preview still moves.
var sampleBuffer = await stillImageOutput.CaptureStillImageTaskAsync(videoConnection);
Console.WriteLine("[CLKJFADSFQXW] THIS DOESN'T SHOW UP");
// var jpegImageAsBytes = AVCaptureStillImageOutput.JpegStillToNSData (sampleBuffer).ToArray ();
var jpegImageAsNsData = AVCaptureStillImageOutput.JpegStillToNSData(sampleBuffer);
Console.WriteLine("[ROIAJDGNQWTG]");
// var image = new UIImage (jpegImageAsNsData);
// var image2 = new UIImage (image.CGImage, image.CurrentScale, UIImageOrientation.UpMirrored);
// var data = image2.AsJPEG ().ToArray ();
imageBuffer = jpegImageAsNsData.ToArray();
Console.WriteLine("[FIOUJGAIDGUQ] Image buffer: "+imageBuffer.Length);
}
if (imageBuffer != null && imageBuffer.Length > 100)
{
using (var ms = new MemoryStream(imageBuffer))
{
var uiimg = UIImage.LoadFromData(NSData.FromStream(ms));
this.Add(new UIImageView(uiimg));
}
}
return imageBuffer;
}
Here is how I set the live preview
// This method runs fine and the camera preview is started as expected
public void SetupLiveCameraStream()
{
try
{
// add a UIView to the renderer
liveCameraStream = new UIView()
{
Frame = new CGRect(0f, 0f, Element.Width, Element.Height),
};
this.Add(liveCameraStream);
// find a camera
var captureDevice = AVCaptureDevice.DefaultDeviceWithMediaType(AVMediaType.Video);
if (captureDevice != null)
{
Console.WriteLine("[ZKSDJGWEHSY] Capture device found"); // not the case on simulator
captureSession = new AVCaptureSession();
videoPreviewLayer = new AVCaptureVideoPreviewLayer(captureSession)
{
Frame = liveCameraStream.Bounds
};
liveCameraStream.Layer.AddSublayer(videoPreviewLayer);
ConfigureCameraForDevice(captureDevice);
captureDeviceInput = AVCaptureDeviceInput.FromDevice(captureDevice);
var dictionary = new NSMutableDictionary();
dictionary[AVVideo.CodecKey] = new NSNumber((int)AVVideoCodec.JPEG);
stillImageOutput = new AVCaptureStillImageOutput()
{
OutputSettings = new NSDictionary()
};
captureSession.AddInput(captureDeviceInput);
captureSession.AddOutput(stillImageOutput);
captureSession.StartRunning();
Console.WriteLine("[OIGAJGUWRJHWY] Camera session started");
}
else
{
Console.WriteLine("[OASDFUJGOR] Could not find a camera device");
}
}
catch (Exception x)
{
Console.WriteLine("[QWKRIFQEAHJF] ERROR:" + x);
}
}
I had this issue, and it turned out I was deadlocking because of a combination of using async/await with Task.Result. At a guess you could be experiencing something similar with your usage of Task.Wait().
The two sections of code:
btnTakePicture.Clicked += await (s,e) => { GetCameraImage().Wait(); };
And:
var sampleBuffer = await stillImageOutput.CaptureStillImageTaskAsync(videoConnection);

Clicking or hovering over multiple images in canvas?

I am working on a project for my programming class. I'd like to essentially have a canvas with a background element (say a room.jpg) and then maybe three interactive objects in the room (lamp.jpg, couch.jpg, desk.jpg). I'd like for it to be that if you hover over the lamp a small box or text pops out, giving you some information. Or maybe have it so if you click an image, the same concept happens. You know, something interactive with the objects in the canvas. Again, I'm new to canvas but we have to use it in our assignment. My current code is:
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
var sources = {
room: 'room.jpg',
title: 'title.jpg'
};
loadImages(sources, function(images) {
context.drawImage(images.room, 0,0);
context.drawImage(images.title, 0,0);
});
}
But from what I understand, it makes the two jpegs a "permanent" canvas element (unable to be messed with). I had been trying to get it so that when I clicked I'd go from the title.jpg to the room.jpg but I've since given up. Essentially, all I want now is just to have the room.jpg appear when the page is first loaded, and have three other png objects on top (as objects in the room). Are these able to be interacted with, or do I have to put the images into the canvas in another way? Thanks for all your help and your patience!
// --- Image Loader ----
var images = {};
var loadedImages = 0;
var pictures = {
room: 'room.jpg',
title: 'title.jpg'
lamp1: 'lampoff.jpg'
lamp2: 'lampon.jpg'
};
function loadImages(sources, callback) {
var numImages = 0;
for(var src in sources)numImages++;
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
// --- Mouse Down Functionality ----
$('#canvas').addEventListener('mouseDown', function(e){
if(e.clientX){
var rect = this.getBoundingClientRect();
if(rect) clickCanvas(e.clientX - rect.left, e.clientY - rect.top)
else clickCanvas(e.clientX - this.offsetLeft, e.clientY - this.offsetTop);
}else if(e.offsetX) clickCanvas(e.offsetX, e.offsetY);
else if(e.layerX) clickCanvas(e.layerX, e.layerY);
else console.warn("Couldn't Determine Mouse Coordinates");
})
var lampOn;
function drawCanvas(showLamp){
lampOn = showLamp;
canvas.width = canvas.width //clears canvas
context.drawImage(images.room, 0,0);
context.drawImage(images.title, 0,0);
if(lampOn){
context.drawImage(images.lamp2, 100,100);
}else{
context.drawImage(images.lamp1, 100,100);
}
}
function clickCanvas(x,y){
console.log('clicked canvas at:',x,y)
if(clickedLamp){
drawCanvas(!lampOn)
}
}
loadImages(pictures, function(images) {
drawCanvas(false)
});
Make sure to replace "clickedLamp" and "#canvas"! The idea here is that you redraw the same canvas, using the same function. Everytime you modify any of it, you rerender ALL of it. See if you can get this example working, it will help clarify alot. If you don't understand something comment

EaselJS: Using updateCache() with AlphaMaskFilter When Dragging Mask

I'm using an imported png with an alpha gradient that I'm setting as a mask that reveals the bitmap it is assigned to. The mask object is draggable (kind of like a flashlight). I know I'm supposed to use an AlphaMaskFilter as one of the filters, and I know I'm supposed to use .updateCache()... I'm just not sure I'm using them correctly?
var stage;
var assetQueue;
var bg;
var bgMask;
var container;
var amf;
$(document).ready(function(){
loadImages();
});
function loadImages()
{
// Set up preload queue
assetQueue = new createjs.LoadQueue();
assetQueue.addEventListener("complete", preloadComplete);
assetQueue.loadManifest([{id:"img_bg",src:"images/Nintendo-logo-red.jpg"}, {id:"img_bg_mask",src:"images/background_mask.png"}]);
}
function preloadComplete()
{
assetQueue.removeEventListener("complete", preloadComplete);
init();
}
function init()
{
stage = new createjs.Stage("stage_canvas");
setBackgrounds();
sizeStage();
$(document).mousemove(function(evt){
trackMouse(evt);
});
}
function trackMouse(evt)
{
var mouseX = evt.pageX;
var mouseY = evt.pageY;
// Move the containing clip around
container.x = mouseX - (bgMask.image.width / 2);
container.y = mouseY - (bgMask.image.height / 2);
// Offset the position of the masked image.
bg.x = -container.x;
bg.y = -container.y;
container.updateCache();
stage.update();
}
function setBackgrounds()
{
bg = new createjs.Bitmap(assetQueue.getResult("img_bg"));
bgMask = new createjs.Bitmap(assetQueue.getResult("img_bg_mask"));
container = new createjs.Container();
container.addChild(bg);
amf = new createjs.AlphaMaskFilter(bgMask.image)
container.filters = [amf];
container.cache(0, 0, bg.image.width, bg.image.height);
stage.addChild(container);
stage.update();
}
function sizeStage()
{
var windowW = 600;
var windowH = 600;
stage.canvas.width = windowW;
stage.canvas.height = windowH;
stage.update();
}
Solution found (for anyone interested). The key is to add the image you want to mask to a container. Move the container to any position you want, then offset the contained image within the container. The code has been updated to reflect this.

iviewer jquery pluggin, center image

I'm using the iviewer plugin with a lightbox and I have issue to center my image everytime it load a new image.
I know that there is a pre-built method center() I just don't undertand how and where to call it.
You can find the function I'm using under. The function is called when I click on an element, it open a box div(#iviewer). In which I would like my image center. I also use a zoom pourcentage at the beginning so my image doesn't fit the box (var viewer).
function open(src, id) {
var firstZoom = true;
$("#iviewer").fadeIn().trigger('fadein');
var viewer = $("#iviewer .viewer").
width(920).
height(560).
iviewer({
src : src,
ui_disabled : true,
zoom : '50%',
initCallback : function() {
var self = this;
},
onZoom : function() {
if (!firstZoom) return;
$("#iviewer .loader").fadeOut();
$("#iviewer .viewer").fadeIn();
firstZoom = true;
}
}
);
//load new pic
viewer.iviewer('loadImage', src);
}
Thanks for the help.
The "onFinishLoad" callback hook in the initialization worked for me:
onFinishLoad: function(ev, src){ viewer.iviewer('center')}

Resources