How to dynamically change images using Metaio - metaio

I have just start learning Metaio. I am working on a simple development test project.
I have so far made the tracking sheet, put image and two arrows (buttons) which means next image and previous image.
For testing I made one of the buttons to display the image and the other for hiding the image. All this works fine so far.
My question is when I added extra images how can I shift the images dynamically back and forward using my next and previous buttons?
My testing code:
button2.onTouchStarted = function () {
image1.hide();
};
button1.onTouchStarted = function () {
image1.display();
};

It can be done different ways, I suggest you to use arel.Scene.getObject and put your image names inside array and each time you click next or previous you count the array key up or down.
I assume you are using Metaio Creator editor.
You have to added codes 3 different places:
Previous (left arrow button)
button1.onTouchStarted = function () {
if (currentImageIndex == firstImageIndex) {
return;
}
arel.Scene.getObject(imageArray[currentImageIndex]).hide();
currentImageIndex--;
arel.Scene.getObject(imageArray[currentImageIndex]).display();
globalsVar['currentImageIndex'] = currentImageIndex;
};
Next (right arrow button)
button2.onTouchStarted = function () {
if (currentImageIndex == lastImageIndex) {
return;
}
arel.Scene.getObject(imageArray[currentImageIndex]).hide();
currentImageIndex++;
arel.Scene.getObject(imageArray[currentImageIndex]).display();
globalsVar['currentImageIndex'] = currentImageIndex;
};
On your Global Script
var imageArray = ["image1", "image2"]; // and so on extra image names
var firstImageIndex = 0;
var lastImageIndex = imageArray.length - 1;
var currentImageIndex = firstImageIndex;
globalsVar = {};
arel.Scene.getObject(imageArray[currentImageIndex]).display();

Related

dc.js : how to wait for complete barchart redraw?

Hy everybody,
I'm working with dc.js and I think it's a genious tool ! However I have a issue I can't solve.
I'm using a dc.barchart and I want to launch a function of mine after a click on one bar, but I need to wait the end of the redraw of the barchart.
Order :
- my barchart is displayed
- I click on one bar
-> the barchart is redraw
-> only after the complete redraw, my function is launched
Where can I put my callback ? I can't find the corresponding code.
_chart.onClick = function (d) {
var filter = _chart.keyAccessor()(d);
dc.events.trigger(function () {
_chart.filter(filter);
_chart.redrawGroup();
alert("here is not working");
});
};
(...)
dc.redrawAll = function(group) {
var charts = dc.chartRegistry.list(group);
for (var i = 0; i < charts.length; ++i) {
charts[i].redraw();
}
alert("neither here");
if(dc._renderlet !== null)
dc._renderlet(group);
};
dc.events.trigger = function(closure, delay) {
if (!delay){
closure();
alert("neither neither here");
return;
}
dc.events.current = closure;
setTimeout(function() {
if (closure == dc.events.current)
closure();
}, delay);
};
Any idea ? I'm completely blocked right now :(
Thanks a lot for your help,
vanessa
If _chart is the name of your chart and you want to execute some function named my_function after finishing drawing, use the following piece of code after the declaration of the chart itself:
_chart.on("postRedraw", my_function);
Hope this is what you were looking for.

How can I launch a website from a button

I know how to use the createAnchor to place a link in a panel, however I would like to launch a link from a button. Is this possible, if so how?
After some trail and error I found an easier way of achieving the goal.
I just create an image of the button showing my desired text and use thse setAttribute method of the anchor.
Unfortunally I stll require an AbsolutePanel.
function doGet()
{
// Problem with Google Apps :
// Not possible to click a Button and show a site
// Solutions found on StackOverflow mostly use :
// a) var panel = createAbsolutePanel --> Necessary to create an Absolute Panel
// b) var image = createImage --> The image to be shown
// c) var anchor = createAnchor --> Anchor making it possible to activate a url
// d) position the anchor on top of the image
// e) make anchor and image of same size
// f) make anchor invisible (by zIndex, opacity or visibility)
//
// One of the people showing how this works is http://stackoverflow.com/users/1368381/serge-insas who's
// efforts inspired me to have a look at other possibilities. (thanks !)
//
// Result : next step in making it easy to overcome a limitation of GAS --> no createImage required anymore
// How : using setAttribute('backgroundImage', Url) method of anchor
// Limitation : still required to create an Absolute panel instead of a Vertical panel --> who's next to improve ??
//
// Author : SoftwareTester, may 13th, 2014
var app = UiApp.createApplication().setTitle("Image Anchor");
var picButton = 'https://drive.google.com/uc?id=0BxjtiwHnjnkrTVJiR1g2SlZTLVE'; // Can on be accessed be a few people
var widthButton = 128;
var heightButton = 24;
var anchor = app.createAnchor("", "http://www.opasittardgeleen.nl")
.setHeight(heightButton).setWidth(widthButton)
// .setHeight("150").setWidth("128") // Nice effect !!
// .setHeight("150").setWidth("512") // Even more
.setStyleAttribute('backgroundImage', 'url(' + picButton + ')');
var panel = app.createAbsolutePanel().setWidth('50%').setHeight('50%');
panel.add(anchor,100,50); // I would like to avoid positioning like this and just add the anchor to a Grid or VerticalPanel
app.add(panel);
return app.close();
}
I have answered a similar post with a workaround that works nicely although it is, I admit, a bit complex in regard to what it does...
Here is a test app
and the code reproduced from the other post is below : I used an invisible anchor superimposed to the image but it could of course be anything else... a button or whatever you want.
function doGet(){
var app = UiApp.createApplication().setStyleAttribute("background", "#CCCCFF").setTitle('Anchor Test')
var top = '100PX';// define dimensions and position
var left = '100PX';
var width = '80PX';
var height = '80PX';
var mainPanel = app.createVerticalPanel();
var customAnchor = app.createHorizontalPanel().setId('usethisId')
addStyle(customAnchor,top,left,width,height,'1','1')
var image = app.createImage("https://dl.dropbox.com/u/211279/Time-change-clock_animated_TR80.gif")
addStyle(image,top,left,width,height,'1','1')
var realAnchor = app.createAnchor('This is the Anchor', 'https://sites.google.com/site/appsscriptexperiments/home')
addStyle(realAnchor,top,left,width,height,'2','0')
customAnchor.add(realAnchor);
customAnchor.add(image)
mainPanel.add(customAnchor);
app.add(mainPanel);
return app;
}
function addStyle(widget,top,left,width,height,z,visibility){
widget.setStyleAttributes(
{'position': 'fixed',
'top' : top,
'left' : left,
'width' : width,
'height':height,
'opacity' : visibility,
'zIndex' : z});
}
EDIT : I forgot to mention this post with a button example... exactly what you wanted : How do I open a web browser using google apps script?
EDIT 2
Following Software tester answer, here is a compact version that one can place in a grid or anywhere else... just place the widget called 'container'.
To illustrate I placed it in a grid in the example below/
link to test
code :
function doGet(){
var app = UiApp.createApplication().setTitle("Image Anchor");
var picButton = 'https://dl.dropboxusercontent.com/u/211279/ProgressSpinner.gif';
var img = app.createImage(picButton).setPixelSize(25,25);
var grid = app.createGrid(5,2);
for(n=0;n<5;n++){
grid.setText(n,0,'some text').setBorderWidth(1);
}
var anchor = app.createAnchor(" - ", "https://sites.google.com/site/appsscriptexperiments/").setStyleAttribute('opacity','0').setPixelSize(25,25);
var container = app.createAbsolutePanel().setPixelSize(25,25);
container.add(img,0,0).add(anchor,0,0);
grid.setWidget(4,1,container);
app.add(grid);
return app;
}
The answer EDIT 2 of Serge Insas provides extra flexibility using a grid.
Improving the world little by little by learning and using each others good ideas, also holds for software of course. Thanks again Serge!
I noticed a few differences that might or might not be of interest in certain situations.
I always try to specify constants (like width and height) and minimize using similar code like .setPixelSize(width, height) making it easier 'not to forget something while changing'. That's why I prefer to avoid creating a separate image object.
Serge Insas uses .setStyleAttribute('opacity','0'); while I'm using .setStyleAttribute('backgroundImage', url); . I don't know what are the pro's and con's of both possibilities.
Below is the generalized code
function doGet()
{ // Generalized version using : image + opacity + container
var app = UiApp.createApplication().setTitle("Image Anchor");
var width = 25;
var height = 25;
var urlImage = 'https://dl.dropboxusercontent.com/u/211279/ProgressSpinner.gif';
var urlAnchor = "https://sites.google.com/site/appsscriptexperiments/";
var grid = createImageAnchor(urlImage, urlAnchor, width, height);
app.add(grid);
return app;
}
and the function createImageAnchor can be
function createImageAnchor(urlImage, urlAnchor, width, height)
{ // Using backgroundImage
var app = UiApp.getActiveApplication();
var anchor = app.createAnchor("", urlAnchor).setPixelSize(width, height)
.setStyleAttribute('backgroundImage', 'url(' + urlImage + ')');
var panel = app.createAbsolutePanel().setPixelSize(width, height).add(anchor, 0, 0);
var grid = app.createGrid(1, 1).setWidget(0, 0, panel); // Create grid and put anchor in it
return grid;
}
or
function createImageAnchor(urlImage, urlAnchor, width, height)
{ // Using opacity
var = UiApp.getActiveApplication();
var image = app.createImage(urlImage).setPixelSize(width, height);
var anchor = app.createAnchor("", urlAnchor) .setPixelSize(width, height)
.setStyleAttribute('opacity','0');
var panel = app.createAbsolutePanel().setPixelSize(width, height)
.add(image, 0, 0).add(anchor, 0, 0); // Same position for image and anchor
var grid = app.createGrid(1, 1).setWidget(0, 0, panel); // Create grid and put image + anchor in it
return grid;
}
Using createImageAnchor makes it easier to use this 'combined object' anywhere in code, especially after adding it into a library.
As I'm new to GAS (started may 7th after 5 years of inactivity) I know I need to learn a lot and would like to know what the pro's and con's of different methods are.

KineticJS - How to Change Image src on Button Click

I'm trying to change the src of an image in my kineticjs stage on a button click.
I have a draggable image (in this case darth-vader) and a static image on top (in this case monkey). On the click of a button i want to be able to replace the draggable image with a new one (yoda)
JSFiddle can be seen here:
http://jsfiddle.net/SkVJu/33/
I thought the following:
btn.addEventListener("click", function (event) {
mainImage.src = path+'yoda.jpg';
layer.removeChildren();
draw(mainImage,true);
draw(foregroundImage,true);
});
would accomplish it: first by updating the src, then removing all objects and redrawing both again in the correct order.
For some reason though i get 2 yoda images placed on the stage - 1 correctly behind but another above everything else...
Instead of removing all the children and adding them back, you can swap image sources easily by using the KineticJS setImage function and passing in a Javascript Image Object: http://kineticjs.com/docs/Kinetic.Image.html#setImage
I updated your draw function so that it takes an id and name so that we can select the Kinetic Image object later:
// Draw function
function draw(image,drag,id,name){
if (typeof id == 'undefined') id = '';
if (typeof name == 'undefined') name = '';
var img = new Kinetic.Image({
image: image,
draggable: drag,
id: id,
name: name
});
layer.add(img);
layer.draw();
return img;
}
and then here is your update click function:
// Change draggable Image
btn.addEventListener("click", function (event) {
layer.get('#mainImageId')[0].setImage(mainImage2); //get the object with id "mainImageId"
layer.draw();
});
jsfiddle
Also, I moved your foregroundImage load function inside the mainImage onload function so that we make sure the Monkey is added to the stage after the mainImage:
// Define draggable image
var mainImage = new Image();
mainImage.onload = function () {
draw(mainImage,true, 'mainImageId');
// Define foreground image
var foregroundImage = new Image();
foregroundImage.onload = function () {
draw(foregroundImage,false);
};
foregroundImage.src = path+'monkey.png';
};
mainImage.src = path+'darth-vader.jpg';
Wouldn't it be easier to load both images right away, create new Kinetic.Group of them, set one visible and other hidden, than just create function that will hide first and show second on click? Just asking cause i have similar issue to deal with, just that in my case exchange should be done among 5 different icons based on settings parameter that user can change...

Clear html5 canvas, then re-initialize it

I'm working on an activity where a user would draw a line chart and check to see how close it is to an actual chart. I've got it working, but need help on 'resetting' the canvas. I can get it to clear, but I need to reinitialize it after it's cleared so the user can try again.
here is the reset code I have so far:
var clearCanvas = false;
function onFrame(event) {
if (clearCanvas && project.activeLayer.hasChildren()) {
project.activeLayer.removeChildren();
clearCanvas = false;
}
}
$('.clear').on('click', function() {
clearCanvas = true;
return false
})
Here is a jsfiddle
I've kinda hacked this code together, as I'm not a coder, so go easy if it's not the best way of doing things. If anyone has a cleaner/more efficient way of doing this I'm all ears!
Thanks in advance.
S
First, your jsfiddle is getting a 404 when it tries to use "http://paperjs.org/static/js/paper.js". Switching that to "https://raw.github.com/paperjs/paper.js/master/dist/paper.js" works for me.
Second, if you want the user to try again, they need to be able to place 7 (or however many) new points after the reset, so in your onFrame function you need to set maxPoints to 0 when clearing the canvas.
Third, the path that connects the users points will need to be re-initialized. That can be done by calling path.removeSegments() and then re-adding path to the activeLayer.
Fourth, once you have removed the children from the activeLayer, fullChart (the "answer") is no longer on the activeLayer. You will have to re-add it and re-set its opacity to 0 (if you want it hidden again).
Putting those together, this onFrame seems to do what you are attempting:
function onFrame(event) {
if (clearCanvas && project.activeLayer.hasChildren()) {
project.activeLayer.removeChildren();
fullChart.opacity = 0;
maxPoints = 0;
path.removeSegments();
project.activeLayer.addChildren([fullChart, path]);
clearCanvas = false;
}
}
Here's a jsfiddle.
Other notes:
I don't believe you have to separate your code like that; you could just clear the canvas in your button's callback instead of waiting for the onFrame. So all of the code in onFrame could go in the callback instead (just without the clearCanvas variable).
I would also recommend using the same Point objects for your myCircle and myPath instead of making new ones with the same coordinates. For example:
var point1 = new Point(72, 214);
var point2 = new Point(205, 177);
...
var point7 = new Point(868, 177);
var myCircle1 = new Path.Circle(point1, 10)
var myCircle2 = new Path.Circle(point2, 10)
....
var myCircle7 = new Path.Circle(point7, 10)
var myPath = new Path([point1, point2, ..., point7]);

OpenLayers - clear 'map' div

I am using OpenLayers to display dynamically loaded images. The code I am using is:
var map;
function init(strURL) {
map = new OpenLayers.Map('map');
var options = { numZoomLevels: 3,
isBaseLayer: true, };
var graphic = new OpenLayers.Layer.Image(
'City Lights',
strURL + "?sc=page",
new OpenLayers.Bounds(-180, -88.759, 180, 88.759),
new OpenLayers.Size(580, 288),
options
);
// graphic.events.on({
// loadstart: function () {
// OpenLayers.Console.log("loadstart");
// },
// loadend: function () {
// OpenLayers.Console.log("loadend");
// }
// });
var jpl_wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
"http://t1.hypercube.telascience.org/cgi-bin/landsat7",
{ layers: "landsat7" }, options);
map.addLayers([graphic, jpl_wms]);
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.zoomToMaxExtent();
}
I am calling this function on a button click event and passing the strURL (sources of the images) at that time. The result is, with each click a different image is loaded and displayed on the web page but is not clearing the previous image. So I 5 different images on the webpage are shown with 5 clicks and so on.
My javascript knowledge is limited, so my apologies if this is a stupid question. How to stop this behavior? Thanks for any assistance.
Also, I didn't quite understand the lines:
var jpl_wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
"http://t1.hypercube.telascience.org/cgi-bin/landsat7",
{ layers: "landsat7" }, options);
But I know these lines are needed since I'm getting js error if I remove them.
So currently you are calling init(strURL) with each button click? Divide that code into two parts:
On page load, create map and layer objects
On button click, just update URL of existing image layer. Image layer has setUrl(url) method for that: http://dev.openlayers.org/apidocs/files/OpenLayers/Layer/Image-js.html#OpenLayers.Layer.Image.setUrl
Here is sample, that should explain it: http://jsfiddle.net/mEHrN/6/
About var jpl_wms = ... - it creates WMS layer, that should display Landsat imagery (but that URL doesn't seem to work). If you remove it, remember also to remove it from map.addLayers:
map.addLayers([graphic]);
Probably this was reason, why you got JS error.