Good afternoon. Is it possible to add a new object property value to its previous value?
I have tried the following code but browser returns "Maximum call stack size exceeded". The property translate will be used to drag a chart horizontally. It will shift the data range of an array that will be painted on the canvas chart. Kind regards.
function drawChart() {
.
.
.
tickerData = [..., ..., ...];
dataLength = tickerData.length;
barSpace = Number(localStorage.getItem("barspace"));
barWidth = (0.7 * barSpace).toFixed(1);
rightSpan = 3 * barSpace;
barStrokeWidth = 1;
if(!(dataLength - dragCanvas.translate() > dataLength)) {
dataLength = dataLength - dragCanvas.translate();
}
else {
dataLength = dataLength;
}
.
.
.
}
var dragCanvas = {
isTrue : false,
drag : [0, 0],
translate : function() {
return this.translate() + Math.ceil((this.drag[1] - this.drag[0])/barSpace);
}
};
function updateChartPaint(e) {
var pointerX = e.clientX;
var pointerY = e.clientY;
if(!dragCanvas.isTrue) {
dragCanvas.drag[0] = pointerX;
dragCanvas.drag[1] = pointerX;
}
else {
dragCanvas.drag[1] = pointerX;
$("#chartCanvas").empty();
drawChart();
}
}
document.addEventListener("mousemove", updateChartPaint, false);
document.getElementById("chartCanvas").onmousedown = function() {
dragCanvas.isTrue = true;
};
document.getElementById("chartCanvas").onmouseup = function() {
dragCanvas.isTrue = false;
};
You are calling this.translate() inside of the translate function so it goes into an infinite loop calling itself until eventually the call stack is exceeded.
From the way translate is called it looks like the function should be defined like this instead:
translate : function() {
const newTranslate = this.oldTranslate + Math.ceil((this.drag[1] - this.drag[0])/barSpace);
this.oldTranslate = newTranslate;
return newTranslate;
}
oldTranslate: 0
I assume that barSpace is declared outside of the function and will be a valid value. It seems to be set from localStorage but if it does not exist, then Number(localStorage.getItem("barspace")) will be zero and the return value from translate will be Infinity. Is that intended?
Also updateChartPaint sets a variable called pointerY but never uses it. Is it correct that dragging in the Y-axis is ignored and only changes in the X-axis matters?
Related
I have 3 clickable objects. When one is clicked, this becomes the 'selected unit'.
I am trying to create some generic actions for the units such as moving to a point.
In my create function I initialize the units, when a unit is clicked on - this is supposed to become the 'selected unit' so that my movement and direction function applies to the this unit. However, the script is not able to recognize which unit intend for example I get this error:
Uncaught TypeError: Cannot read property 'velocity' of undefined.
Is there a way to use a variable to indicate selected users and pass that to the functions?
window.onload = function() {
var block_count = 0;
var block = '';
var selected_unit = '';
var unit_clicked = 0;
var tank1 = null;
var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update, render: render});
function preload () {
game.load.image('block', 'block.png');
game.load.image('tank1', 'tank.png');
game.load.image('baddie', 'tank.png');
game.load.image('mouse_btn', 'block.png');
game.input.mouse.capture = true;
}
function create () {
game.physics.startSystem(Phaser.Physics.ARCADE);
mouse_btn = game.add.sprite(30,30, 'mouse_btn');
mouse_btn.anchor.setTo(0.5, 0.5);
//T1
tank1 = game.add.sprite(30,30, 'tank1');
initialise_player(tank1);
game.physics.enable(tank1, Phaser.Physics.ARCADE);
//T2
tank2 = game.add.sprite(30,60, 'tank1');
initialise_player(tank2);
game.physics.enable(tank2, Phaser.Physics.ARCADE);
game.world.setBounds(0, 0, 2000, 2000);
game.camera.follow(tank1);
}
function update () {
if(selected_unit == '') {
mouse_btn.x = game.input.mousePointer.worldX
mouse_btn.y = game.input.mousePointer.worldY
}
if(game.input.activePointer.leftButton.isDown && block_count == 0 && unit_clicked == 0) {
game.input.activePointer.leftButton.stop(event);
block_count =1;
block = game.add.sprite(game.input.mousePointer.worldX, game.input.mousePointer.worldY, 'block');
game.physics.enable(block, Phaser.Physics.ARCADE);
block.anchor.setTo(0.5, 0.5)
lookAtObject(selected_unit, block, 0.005);
}
if(block.alive){
game.physics.arcade.moveToObject(selected_unit, block, 260, 0)
} else {
console.log(selected_unit)
selected_unit.body.velocity.x = 0;
selected_unit.body.velocity.y = 0;
}
if(game.physics.arcade.collide(selected_unit, block)) {
block_count--;
block.kill();
}
}
function render(){
//console.log(game.physics.arcade.collide(tank1, block))
}
function lookAtObject(obj, target, rotspeed){
var angle = Math.atan2(block.y - tank1.y, block.x - tank1.body.x);
tank1.rotation = angle + game.math.degToRad(90);
}
function initialise_player(tank1){
tank1.anchor.setTo(0.5, 0.5);
tank1.inputEnabled = true;
tank1.input.useHandCursor = true;
tank1.events.onInputDown.add(t1_clicked,this);
tank1.events.onInputOver.add(t1_over, this)
tank1.events.onInputOut.add(t1_out, this)
}
function t1_clicked() {
selected_unit = tank1;
}
function t1_over() {
unit_clicked = 1
}
function t1_out () {
unit_clicked = 0
}
};
The error you're getting on initial load is because in update you're making an assumption that selected_unit exists and has a body.
Update your third if to make sure selected_unit is defined.
if (selected_unit !== '') {
selected_unit.body.velocity.x = 0;
selected_unit.body.velocity.y = 0;
}
However, a better option would be to put this a few lines down, where you kill the block instead.
if(game.physics.arcade.collide(selected_unit, block)) {
selected_unit.body.velocity.x = 0;
selected_unit.body.velocity.y = 0;
block_count--;
block.kill();
}
if (block.alive); moveToObject is also expecting selected_unit to exist and have a body, which may not be the case; wrap it with a check.
if (selected_unit !== '') {
game.physics.arcade.moveToObject(selected_unit, block, 260, 0)
}
That now allows tank1 to rotate to look at the item you just placed, but it doesn't move it until it or tank2 have been clicked on.
This also points out that there are a number of tweaks you'll want to make to your code in general, since you're ignoring arguments that are being passed in. For example, t1_clicked isn't using the sprite that's been clicked on, but is instead just hard-coding tank1. lookAtObject isn't using obj or target, but again has values hard-coded in.
One other thing you may want to change is the following:
if(selected_unit == '') {
mouse_btn.x = game.input.mousePointer.worldX
mouse_btn.y = game.input.mousePointer.worldY
}
If you make that the following, you won't end up with an extra sprite hanging about on the screen.
if (block_count === 0) {
mouse_btn.x = game.input.mousePointer.worldX;
mouse_btn.y = game.input.mousePointer.worldY;
}
I have a slideshow on my website with left and right buttons.
Like this (http://i.prntscr.com/863ad10cfd4e4f1ea9b90721cc6582e8.png).
I am using angular to change the image on left and right.
As you can see in the function I increase the value
/*SlideShow Pictures*/
$scope.picture_1 = "./images/photos/watch.jpg";
$scope.picture_2 = "./images/photos/watch.jpg";
$scope.picture_3 = "./images/photos/watch.jpg";
$scope.picture_4 = "./images/photos/watch.jpg";
$scope.picture = $scope.picture_1;
$scope.picture_value = 1;
$scope.image_change_right = function () {
if ($scope.picture_value < 4)
{
$scope.picture_value = $scope.picture_value + 1;
$scope.picture = ('$scope.picture_' + $scope.picture_value);
console.log($scope.picture_value);
}
else{
$scope.picture_value = 1;
$scope.picture = ('$scope.picture_' + $scope.picture_value);
console.log($scope.picture_value);
}
}
Above is the function called for button right press.
The function increases the variable by 1 and adds it to the string to call the new variable. In the console log it looks great! However I think it is only showing as a string --- it is not actually setting the value of scope.picture to the variable.
How can I set this to not be a string but as a valid variable?
Thanks everyone!
A better way would be like this:
The Controller:
// The array of picture links.
$scope.pictures = [
"./images/photos/watch.jpg",
"./images/photos/watch.jpg",
"./images/photos/watch.jpg",
"./images/photos/watch.jpg"
];
$scope.current = 0; // Initialize the current pictures place in the array.
$scope.picture = $scope.pictures[$scope.current]; // Set the current picture.
// The direction is either 1 or -1;
$scope.changePicture = function (direction) {
$scope.current += direction; // add or remove one depending on direction.
$scope.current %= $scope.pictures.length; // Normalize the number based on the length of the pictures array.
console.log($scope.picture);
}
The Html:
<img src="{{picture}}">
<button ng-click="changePicture(1)">Next</button>
<button ng-click="changePicture(-1)">Previous</button>
Why don't you use an array with image links like this?
/*SlideShow Pictures*/
$scope.pictures = ["./images/photos/watch.jpg", "./images/photos/watch.jpg", "./images/photos/watch.jpg", "./images/photos/watch.jpg"];
$scope.picture = $scope.pictures[0];
$scope.picture_value = 0;
$scope.image_change_right = function () {
if ($scope.picture_value < 4)
{
$scope.picture_value = $scope.picture_value + 1;
$scope.picture = $scope.pictures[$scope.picture_value];
console.log($scope.picture_value);
}
else{
$scope.picture_value = 0;
$scope.picture = $scope.pictures[$scope.picture_value];
console.log($scope.picture_value);
}
}
I have two functions. In the first one I increase a variable by adding 100 to it and I put a setInterval so the funcion repeats itself after some time. The other function is a class, a contrusctor to create an object. I want this.x_origen to get increased by adding aumento to it after some time and repeat it. However what I'm getting here is that the first function increases aument and then it finishes and then the second function starts. How can I solve this?
var aument = 0;
function aumento(){
aument = aument + 100;
return aument;
}
setInterval(function () {aumento()}, 1000/50);
function create_class_brick (x_origen_in, y_origen_in, x_final_in, y_final_in, mi_estado, mi_velocidad, mi_id){
this.x_origen = x_origen_in + aumento();
this.y_origen = y_origen_in;
this.x_final = x_final_in + aumento();
this.y_final = y_final_in;
this.estado = mi_estado;
this.velocidad = mi_velocidad;
this.id_elemento = mi_id;
this.DESPLAZAR_LADRILLO = desplazar_ladrillo;
this.F0 = f0;
this.F2 = f2;
this.crear_ladrillo = crear_ladrillo;
this.obtener_x_origen_ladrillo = obtener_x_origen_ladrillo;
this.obtener_y_origen_ladrillo = obtener_y_origen_ladrillo;
this.obtener_x_final_ladrillo = obtener_x_final_ladrillo;
this.obtener_y_final_ladrillo = obtener_y_final_ladrillo;
}
An example on how to wait for the initial call:
function brick (x_origen_in){
this.x_origen = x_origen_in;
}
function aumento(brick){
console.log(brick.x_origen);
brick.x_origen += 100;
setTimeout(aumento.bind(this, brick), 500);
}
var brick = new brick(100);
aumento(brick);
http://jsfiddle.net/x6c08u39/
You can use Object.defineProperty to dynamically generate the value whenever it is accessed.
First, lets simplify the auto-incrementing of aument:
var aument = 0;
function aumento(){
aument += 100;
}
// The first argument for setInterval is the function to execute
// No need to figure out the interval value at runtime as there are no dynamic values
setInterval(aumento, 20); // 1000/50 === 20
Now lets make an object that will have a the correct value:
function create_class_brick (x_origen_in, y_origen_in, x_final_in, y_final_in, mi_estado, mi_velocidad, mi_id){
Object.defineProperty(this, 'x_origen', {
get: function () { return x_origen_in + aument; }
});
// Other stuff
// ...
}
A quick test:
> aument
34100
> var obj = new create_class_brick(23);
undefined
> obj.x_origen
161523
> obj.x_origen
167223
> obj.x_origen
172423
Well i have this SVG canvas element, i've got to the point so far that once a user clicks and drags the canvas is moved about and off-screen elements become on screen etc....
However i have this is issue in which when ever the user then goes and click and drags again then the translate co-ords reset to 0, which makes the canvas jump back to 0,0.
Here is the code that i've Got for those of you whio don't wanna use JS fiddle
Here is the JSfiddle demo - https://jsfiddle.net/2cu2jvbp/2/
edit: Got the solution - here is a JSfiddle DEMO https://jsfiddle.net/hsqnzh5w/
Any and all sugesstion will really help.
var states = '', stateOrigin;
var root = document.getElementById("svgCanvas");
var viewport = root.getElementById("viewport");
var storeCo =[];
function setAttributes(element, attribute)
{
for(var n in attribute) //rool through all attributes that have been created.
{
element.setAttributeNS(null, n, attribute[n]);
}
}
function setupEventHandlers() //self explanatory;
{
setAttributes(root, {
"onmousedown": "mouseDown(evt)", //do function
"onmouseup": "mouseUp(evt)",
"onmousemove": "mouseMove(evt)",
});
}
setupEventHandlers();
function setTranslate(element, x,y,scale) {
var m = "translate(" + x + "," + y+")"+ "scale"+"("+scale+")";
element.setAttribute("transform", m);
}
function getMousePoint(evt) { //this creates an SVG point object with the co-ords of where the mouse has been clicked.
var points = root.createSVGPoint();
points.x = evt.clientX;
points.Y = evt.clientY;
return points;
}
function mouseDown(evt)
{
var value;
if(evt.target == root || viewport)
{
states = "pan";
stateOrigin = getMousePoint(evt);
console.log(value);
}
}
function mouseMove(evt)
{
var pointsLive = getMousePoint(evt);
if(states == "pan")
{
setTranslate(viewport,pointsLive.x - stateOrigin.x, pointsLive.Y - stateOrigin.Y, 1.0); //is this re-intializing every turn?
storeCo[0] = pointsLive.x - stateOrigin.x
storeCo[1] = pointsLive.Y - stateOrigin.Y;
}
else if(states == "store")
{
setTranslate(viewport,storeCo[0],storeCo[1],1); // store the co-ords!!!
stateOrigin = pointsLive; //replaces the old stateOrigin with the new state
states = "stop";
}
}
function mouseUp(evt)
{
if(states == "pan")
{
states = "store";
if(states == "stop")
{
states ='';
}
}
}
In your mousedown function, you are not accounting for the fact that the element might already have a transform and you are just overwriting it.
You are going to need to either look for, and parse, any existing transform. Or an easier approach would be to keep a record of the old x and y offsets and when a new mousedown happens add them to the new offset.
I am using Jasmine for JS testing, and unfortunately I can't get the following test to pass.
it('should know the total game score', function() {
frame1 = new Frame;
frame2 = new Frame;
game = new Game;
frame1.score(3, 4);
frame2.score(5, 5);
expect(game.totalScore()).toEqual(17)
});
The error message I get is as follows: Error: Expected 0 to equal 17.
The code is as follows:
function Game() {
this.scorecard = []
};
Game.prototype.add = function(frame) {
this.scorecard.push(frame)
};
// Why is this not working!!???
Game.prototype.totalScore = function() {
total = 0;
for(i = 0; i < this.scorecard.length; i++)
{
total +=this.scorecard[i].rollOne + this.scorecard[i].rollTwo;
}
return total;
};
function Frame() {};
Frame.prototype.score = function(first_roll, second_roll) {
this.rollOne = first_roll;
this.rollTwo = second_roll;
return this
};
Frame.prototype.isStrike = function() {
return (this.rollOne === 10);
};
Frame.prototype.isSpare = function() {
return (this.rollOne + this.rollTwo === 10) && (this.rollOne !== 10)
};
Adding the numbers together manually seems to work e.g. total = game.scorecard[0].rollOne + this.scorecard[0].rollTwo , but the for loop (even though it looks correct) doesn't seem to work. Any help would be greatly appreciated :)
I am not pretty sure, but it seems that you are not calling the "Add" method, so no data is added to the scorecard.
You have to add the Frames to your game i guess
it('should know the total game score', function () {
frame1 = new Frame;
frame2 = new Frame;
game = new Game;
// those lines are missing
game.add(frame1);
game.add(frame2);
frame1.score(3, 4);
frame2.score(5, 5);
expect(17).toEqual(game.totalScore())
});
otherwise, the scorecard-array is empty and the total score is therefore equal to 0.
missing (so no data is added to the scorecard.)
game.Add(frame1);
game.Add(frame2);