Clear html5 canvas, then re-initialize it - html

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]);

Related

Cocos2d-x JS getting variables from scene or layer

I'm currently having issues with the following problem.
I'm trying to access the layer inside the scene and thereby the elements that I set in that layer. In this case I want access to the conv_label in the Layer to set the text.
I'm doing this via a ConversationClass which extends cc.Class.
When I try to access the layer via the variable it doesn't work or with getChildByName or Tag it doesn't work (value is always null).
This is a method inside the ConversationClass, I can console log the currentscene without any problem, but any variable I set doesn't appear in the current scene. in this case the name was "conv_layer", I can access the children by just using array calls, but that's not really a good way it seems and quite confusing.
This I tried:
currentscene.children[0].children[3] will give me the right element.
currentscene.conv_layer.getChildByName("text") says conv_layer does not exist
currentscene.children[0].getChildByName("text") returns null
Does anyone know how to solve this issue or can tell me where my thinking went wrong?
Not sure of it matters, but I call the scene (for now) in the following way.
cc.LoaderScene.preload(conversation_load, function() {
cc.director.runScene(new ConversationScene());
this.startGame();
}, this);
This is where I want access
startConversation: function(conversation) {
this._conversationObject = conversation;
this._currentScene = cc.director.getRunningScene();
console.log(this._currentScene); // Shows current scene object (doesn't have conv_layer property)
if(scene !== null)
this._currentConversationLayer = scene.conv_layer; // Returns null
},
This is my scene:
var ConversationScene = cc.Scene.extend({
conv_layer: null,
onEnter: function() {
this._super();
this.conv_layer = new ConversationLayer();
this.conv_layer.setName('conversation');
this.conv_layer.setTag(1);
this.addChild(this.conv_layer);
}
});
and this is my layer:
var ConversationLayer = cc.Layer.extend({
ctor: function() {
this._super();
this.init();
},
init: function() {
this._super();
var winSize = cc.director.getWinSize();
GD.current_conversation = conversation1;
this.background = new cc.Sprite();
this.background.anchorX = 0.5;
this.background.anchorY = 0.5;
this.background.setPositionX(winSize.width / 2);
this.background.setPositionY(winSize.height / 2);
this.addChild(this.background);
this.girl = new cc.Sprite();
this.girl.anchorX = 0;
this.girl.anchorY = 0;
this.addChild(this.girl);
this.text_background = new cc.Sprite(resources.conversation_interactive_assets, cc.rect(0,0,1920/GD.options.scale,320/GD.options.scale));
this.text_background.anchorX = 0.5;
this.text_background.anchorY = 0;
this.text_background.setPositionX(winSize.width / 2);
this.text_background.setPositionY(0);
this.addChild(this.text_background);
// Left
this.conv_label = new cc.LabelBMFont("", resources.font);
this.conv_label.anchorX = 0;
this.conv_label.anchorY = 0;
this.conv_label.setPositionX((winSize.width - this.text_background.width) / 2 + 20);
this.conv_label.setPositionY(this.text_background.height - 30);
this.conv_label.color = cc.color.BLACK;
this.conv_label.setName('text');
this.addChild(this.conv_label);
}
});
The issue was the loading order of everything.
It seems scenes are loaded in async, so the next function would be called but no layer would exist at that point.
Solved it by doing creation inside the class itself and calling onSceneEnter.

How do I dynamically add an object to my Flex 3 Array Collection?

I have thoroughly searched, but have not found an answer to this question. Maybe my question is wrong. I have a total of 30 Children on each Canvas child of my tabNavigator. The code works well for counting and iterating through the children, but when I attempt to add an item to my ArrayCollection, it all falls apart. Here's the code:
private function addrNewDB():void {
var q:int = 0;
var t:int = tabNavigator.numChildren;
while (q<t){
var TNG:Array = tabNavigator.getChildren();
var qnn:Array = TNG[q].getChildren() as Array;
var gat:int = 0;
var pat:int = TNG[q].numChildren;
var newItem:Object = new Object();
while (gat<pat){
if (UIComponent(qunn[gat]) is CheckBox){
if (qunn[gat].selected == true){
var game:String = "Y";
}
else {
gm = "N";
}
Alert.show("gat: "+String(gat)+" | pat: "+String(pat)+"\n"+qnn[gat].id+" - "+qnn[gat].label+": "+gm);
}
gat++;
}
q++;
}
}
What's going on here is that I have tabs that are dynamically added at runtime with a button. Each tab has a canvas upon which are textboxes, labels, checkboxes, and a combobox. There are 30 items in total; seven of them are checkboxes.
I have set up this code to iterate through each child (component) of each Canvas child (pat) of each Tab(t) in my tabNavigator, determine if the component is a CheckBox, see if it is selected, and then Alert me for only the 7 CheckBoxes on each Canvas.
All of this works well. Where I run into a snag is when I attempt to add the new item to the HardwareItems ArrayCollection.
I think that I am just not getting the syntax right. When I try to place some code to add a new item to HardwareItems right after the Alert, it stops Alerting me after the first CheckBox, so I am assuming that it is running into an issue of some kind with the way I've been coding it.
What I would like is some help in correctly adding a new item to the HardwareItems array collection for each of the 7 checkboxes.
I have tried this:
HardwareItems.addItem({merch: lblMerchID.text,
item: qnn(gat).label,
manf: "",
have: gm,
requ: "",
qual: "",
location: "",
id: qnn(gat).id});
and this:
newItem['merch'] = lblMerchID.text;
newItem['item'] = qnn(gat).label;
newItem['qual' = "";
newItem['loc'] = "";
newItem['id'] = qnn(gat).id;
HardwareItems.addItem(newItem);
HardwareItems.refresh();
and this too:
newItem.merch = lblMerchID.text;
newItem.item = qnn(gat).label;
newItem.qual = "";
newItem.loc = "";
newItem.id = qnn(gat).id;
HardwareItems.addItem(newItem);
HardwareItems.refresh();
It's obvious that these are all incorrect ways to accomplish what I want, but I'm just trying anything. Incidentally, none of these coding atrocities threw any errors. When I tried them, though, I got one alert... the first CheckBox which is at 23 out of 30 items.
I've read up on all the documentation about ArrayCollection and Array syntax, and I guess I just don't get it. Any help is appreciated. Thank you.
addItem() method should work anyway.
Please, make sure that you:
initialize collection before filling it out:
HardwareItems = new ArrayCollection();
initialize objects before filling it out:
newItem = {};
Anyway, remember, that ArrayCollection has a property 'source', which is actually an array.
So, instead of addItem you may use the push() method as following:
var HardwareItems:ArrayCollection = new ArrayCollection();
var newItem:Object = {};
newItem['merch'] = lblMerchID.text;
newItem['item'] = qnn(gat).label;
newItem['qual' = "";
newItem['loc'] = "";
newItem['id'] = qnn(gat).id;
HardwareItems.source.push(newItem);
HardwareItems.refresh();

Disable zoom with Openlayers

i'm using OpenLayers to display custom OSM maps on my website.
I've some points to respect: the map have to be fix (meaning that we can't drag it or zoom it).
I have a problem with the zoom, i can't manage to disable zoom with the mouse. Does anyone has a tip?
map = new OpenLayers.Map('map');
map.events.remove("move");
map.events.remove("movestart");
map.events.remove("moveend");
map.events.remove("zoomend");
map.events.remove("mouseover");
map.events.remove("mouseout");
map.events.remove("mousemove");
map.events.remove("zoomstart");
var nav = new OpenLayers.Control.Navigation({
defaultDblClick: function(event) { return ; }
});
map[index].addControl(nav);
Also, if someone has a tip to remove all Navigation events easier than that, it would be greatly appreciated.
Disable the default controls on your map by passing an empty array:
var map = new OpenLayers.Map('map', { controls: [] });
For OpenLayers3 the interaction array also needs to be empty.
var map = new ol.Map({
controls: [],
interactions: []
});
Simplifying approach of Mahdi results in
var i, l, c = map.getControlsBy( "zoomWheelEnabled", true );
for ( i = 0, l = c.length; i < l; i++ ) {
c[i].disableZoomWheel();
}
This way disabling zoom on mouse wheel doesn't require to customize options on constructing map e.g. by creating map without any control (though this was somewhat requested by Lght). In addition re-enabling zoom works equivalently.
In addition, by searching controls matching enabled property zoomWheelEnabled rather than class name it's supporting custom controls derived from OpenLayers.Control.Navigation.
You can do the following also:
map = new OpenLayers.Map({
// options here ...
}
var Navigation = new OpenLayers.Control.Navigation({
'zoomWheelEnabled': false,
'defaultDblClick': function ( event ) {
return;
}
});
map.addControl(Navigation);
var NavigationControls = map.getControlsByClass('OpenLayers.Control.Navigation')
, i;
for ( i = 0; i < NavigationControls.length; i++ ) {
NavigationControls[i].disableZoomWheel();
}
Found here.
For other options like disable dragging, you can take a look at the documentation and customize the above code.
Here is another easy way to restrict the zoom event based on some logic. Because OpenLayers doesnt provide a 'beforezoom'
map.zoomToProxy = map.zoomTo;
map.zoomTo = function (zoom,xy){
// if you want zoom to go through call
map.zoomToProxy(zoom,xy);
//else do nothing and map wont zoom
};
How this works:
For any kind of zooming activity, OpenLayers API ultimately calls the function called zoomTo. So before overriding it, we copy that function to a new function called 'zoomToProxy'. The we override it and add our conditional zoom logic. If we want the zoom to happen we just call new proxy function :)
You could reset the controls array and then add the Zoom and TouchNavigation to it.
var map_controls = [];
map_controls.push( new OpenLayers.Control.Zoom() );
map_controls.push( new OpenLayers.Control.TouchNavigation() );
var map = new OpenLayers.Map({
div: "map",
controls: map_controls
});
Hope it helps ! :)

Flash as3 show specific movie clip on click

I just started using flash so this might be a simple thing so please be patient.
I'm doing a project were I have a map and you can click the places on the map and the info appears. I could manage to link every button_btn to every info_mc but that would take forever, so I tried to make a function that would read the buttons name and redirect to the info_mc itself. However since the name is being converted to string when I change from name_mc to name_info it is not redirecting. Here is the code.
winterfell_info.visible = false;
map.winterfell_btn.doubleclickEnabled = true;
map.winterfell_btn.mouseChildren = doubleClickEnabled;
map.winterfell_btn.addEventListener(MouseEvent.DOUBLE_CLICK, show_clicked);
function show_clicked(e:MouseEvent):void{
var get_name = e.currentTarget.name;
var open_info_string = get_name.slice(0,-3) + "info";
//I've tried some things here but nothing is working for me.
var open_info = stage.getChildByName(open_info_string);
open_info.visible = true;
}
Any help would be very much appreciated, thank you.
And if you wondering yes its a map for Game of Thrones.
Remove quotes around "open_info_string", as a first measure, and change the capital S in that string to normal one "s", because Actionscript is case sensitive.
var open_info = stage.getChildByName(open_info_string);
Then, if it wouldn't work at once, insert a trace(open_info_string); before you try to reach the movie clip, to find out whether it was cropped correctly.
i've done something similar.. i don't have time to adapt the code, but if you look at what I did here I believe it'll help you. I'm making an array with the instance names of objects on my video player and then created a function which adds the appropriate event listener using a switch case statement.. easiest way to do this in mass, in my opinion.
var buttons:Array = [clicky,pauseBtn,playBtn];
for (var i in buttons)
{
buttons[i].buttonMode = buttons[i].useHandCursor = true;
addEventListner(buttons[i]);
}
function addEventListner(movieClip)
{
movieClip.addEventListener(MouseEvent.CLICK, function(e){
e.stopPropagation();
switch (movieClip.name)
{
case "playBtn" :
youTubeHolder.videoPlayer.playVideo();
videoController.playBtn.visible = false;
videoController.pauseBtn.visible = true;
break;
case "pauseBtn" :
youTubeHolder.videoPlayer.pauseVideo();
videoController.playBtn.visible = true;
videoController.pauseBtn.visible = false;
break;
case "stopBtn" :
youTubeHolder.videoPlayer.seekTo(0);
youTubeHolder.videoPlayer.stopVideo();
break;
default :
trace(movieClip.name+"is not a valid button");
}
});
}

Mootools reuse same function on multiple instances with something like the each function

I'm using the mootools wall plugin, Its working well in my application, however if I add multiple (image) walls it only works for one wall ::: My understanding of scripting is not good enough to add a each function or similar :::
I need to "bind" the code below to say 2 divs like this :::
My First wall:
<div id="viewport">
<div id="wall">
Second wall:
<div id="viewport">
<div id="wall_02">
Any assistance would be appreciated.
var wallIMAGES = new Wall( "wall", {
"width": scArray[1],
"height": scArray[1],
callOnUpdate: function(items){
items.each(function(e, i){
var el = wall[counterFluid];
if (el) {
var a = new Element("img[width="+scArray[1]+"][height="+scArray[1]+"][src={thumb}]".substitute(el));
a.inject(e.node).set("opacity", 0).fade("in");
e.node.store("tubeObject", el);
}
counterFluid++;
// Reset counter
if( counterFluid >= scArray[10].length) counterFluid = 0;
})
}
});
wallIMAGES.initWall();
Maybe something like this:
var my_wall_ids = ['wall', 'wall_02'];
var myWalls = [];
var baseWallOptions = {
"width": scArray[1],
"height": scArray[1],
callOnUpdate: function(items){
items.each(function(e, i){
var el = wall[counterFluid];
if (el) {
var a = new Element("img[width="+scArray[1]+"][height="+scArray[1]+"][src={thumb}]".substitute(el));
a.inject(e.node).set("opacity", 0).fade("in");
e.node.store("tubeObject", el);
}
counterFluid++;
// Reset counter
if( counterFluid >= scArray[10].length) {counterFluid = 0;}
}); // end items.each
}
}
for (var i=0;i<my_wall_ids.length;i++){
var id = my_wall_ids[i];
var wallOptions = baseWallOptions;
// if your customization was something like changing
// the height , but only on the 'wall' element
if (id === 'wall') {
wallOptions.height = 400;
}
myWalls[i] = new Wall(id, wallOptions);
myWalls[i].initWall();
}
If you read Wall's documentation, you'll notice that, just like most other classes, the first argument it takes is an element id.
So, if your initialization code states
new Wall("wall", { …
…then it will be applied to the element that has the id "wall".
You could simply duplicate your code and use one with "wall", the other one with "wall_02". However, that would be bad practice. Indeed, if you later wanted to change some options, you'd have to do it in two distinct blocks, and they would probably get out of sync.
If your only difference lies in the target id, and the options are to be shared, simply store the options object (second parameter to the Wall class) in a variable and use it twice! That is:
var wallOptions = { width: … };
var wallImages = new Wall("wall", wallOptions),
wallImages2 = new Wall("wall_02", wallOptions);
wallImages.initWall();
wallImages2.initWall();
It could be even better to embed initalization in a function, but this solution is probably the easiest if you simply want to have two Wall instances without learning much more about JS.