I am creating an interactive Maths quiz with 9 triangles generated as objects. The user selects a triangle from a drop-down list and its image and dimensions appear and a variable (thisOne) is set as the number of the triangle (1 to 9).
The user inputs their answer (the area of the triangle).
I would have thought that I could generate the correct answer with something like this
correctAnswer = ("triangle_"+ thisOne).triArea()
but it doesn't work.
My basic question is how do I access the properties or methods of an individual object in a list of objects?
Any help appreciated
<!-- ---------------- Triangle object ----------------- -->
function Triangle(triSrc, triName, triBase, triHeight, triUnits){
this.triSrc = triSrc;
this.triName = triName;
this.triBase = triBase;
this.triHeight = triHeight;
this.triArea = function(){
return triBase * triHeight /2
};
this.triUnits = triUnits;
}
var triangle_1 = new Triangle('tri_q_area_1','right angle triangle',34,20,'m2');
var triangle_2 = new Triangle('img/tri_q_area_2.png','right angle triangle',16,16,'cm2');
var triangle_3 = new Triangle('img/tri_q_area_3.png','right angle triangle',15,8,'km2');
var triangle_4 = new Triangle('img/tri_q_area_4.png','right angle triangle',15,9,'cm2');
var triangle_5 = new Triangle('img/tri_q_area_5.png','scalene', 20,12,'cm2');
var triangle_6 = new Triangle('img/tri_q_area_6.png','scalene', 200,130,'cm2');
var triangle_7 = new Triangle('img/tri_q_area_7.png','scalene', 20,16,'m2');
var triangle_8 = new Triangle('img/tri_q_area_8.png','scalene', 28,16,'km2');
var triangle_9 = new Triangle('img/tri_q_area_9.png','scalene', 54,38,'yards2');
are you ok with have a list?
<!-- ---------------- Triangle object ----------------- -->
function Triangle(triSrc, triName, triBase, triHeight, triUnits){
this.triSrc = triSrc;
this.triName = triName;
this.triBase = triBase;
this.triHeight = triHeight;
this.triArea = function(){
return triBase * triHeight /2
};
this.triUnits = triUnits;
}
var triangles [
new Triangle('tri_q_area_1','right angle triangle',34,20,'m2'),
new Triangle('img/tri_q_area_2.png','right angle triangle',16,16,'cm2'),
new Triangle('img/tri_q_area_3.png','right angle triangle',15,8,'km2'),
new Triangle('img/tri_q_area_4.png','right angle triangle',15,9,'cm2'),
new Triangle('img/tri_q_area_5.png','scalene', 20,12,'cm2'),
new Triangle('img/tri_q_area_6.png','scalene', 200,130,'cm2'),
new Triangle('img/tri_q_area_7.png','scalene', 20,16,'m2'),
new Triangle('img/tri_q_area_8.png','scalene', 28,16,'km2'),
new Triangle('img/tri_q_area_9.png','scalene', 54,38,'yards2')
];
and then do triangles[thisOne].triArea()
You should use an array for this sort of thing. Here's an example:
<!-- ---------------- Triangle object ----------------- -->
function Triangle(triSrc, triName, triBase, triHeight, triUnits){
this.triSrc = triSrc;
this.triName = triName;
this.triBase = triBase;
this.triHeight = triHeight;
this.triArea = function(){
return triBase * triHeight /2
};
this.triUnits = triUnits;
}
var triangle = []; // declare the array;
// note that i'm skipping index 0 to keep with your sample, that is not normally a smart thing to do!
// assign to indices of the array, no need to declare individual elements.
triangle[1] = new Triangle('tri_q_area_1','right angle triangle',34,20,'m2');
triangle[2] = new Triangle('img/tri_q_area_2.png','right angle triangle',16,16,'cm2');
triangle[3] = new Triangle('img/tri_q_area_3.png','right angle triangle',15,8,'km2');
triangle[4] = new Triangle('img/tri_q_area_4.png','right angle triangle',15,9,'cm2');
triangle[5] = new Triangle('img/tri_q_area_5.png','scalene', 20,12,'cm2');
triangle[6] = new Triangle('img/tri_q_area_6.png','scalene', 200,130,'cm2');
triangle[7] = new Triangle('img/tri_q_area_7.png','scalene', 20,16,'m2');
triangle[8] = new Triangle('img/tri_q_area_8.png','scalene', 28,16,'km2');
triangle[9] = new Triangle('img/tri_q_area_9.png','scalene', 54,38,'yards2');
// now you only need the index to address a specific element:
var correctIndex = 4;
var correctAnswer = triangle[correctIndex];
// visualize it in the console
console.log(correctAnswer);
I've searched high and wide for an answer but can't seem to find it. I am trying to alter my custom function that looks up sitemap URL's and the date they were updated to accept a range of inputs.
Here is the current function that works:
function sitemap(sitemapUrl, namespace) {
var array = [];
var xml = UrlFetchApp.fetch(sitemapUrl).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement();
var sitemapNameSpace = XmlService.getNamespace("http://www.sitemaps.org/schemas/sitemap/0.9");
var urls = root.getChildren('url', sitemapNameSpace);
for (var i = 0; i < urls.length; i++) {
var loc = urls[i].getChild('loc', sitemapNameSpace).getText();
var lastmod = urls[i].getChild('lastmod', sitemapNameSpace).getText();
array.push([loc, lastmod]);
}
return array;
}
I've tried using Google's example below but doesn't seem to work however I incorporate it into my function. Any ideas?
function DOUBLE(input) {
if (input.map) { // Test whether input is an array.
return input.map(DOUBLE); // Recurse over array if so.
} else {
return input * 2;
}
}
Edit: This is how I tried to use Google's example for my function:
function sitemaps(sitemapUrl) {
var array = [];
var xml = UrlFetchApp.fetch(sitemapUrl).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement()
var sitemapNameSpace = XmlService.getNamespace("http://www.sitemaps.org/schemas/sitemap/0.9")
var urls = root.getChildren('url', sitemapNameSpace)
for (var i = 0; i < urls.length; i++) {
var loc = urls[i].getChild('loc',sitemapNameSpace).getText();
var lastmod = urls[i].getChild('lastmod',sitemapNameSpace).getText();
array.push([loc, lastmod]);
}
if (sitemapUrl.map) {
return sitemapUrl.map(sitemaps);
} else {
return array
}
You are no using the same format as the Google example. As of right now you are checking if the input is an array after actually retrieving the data.
But you using fetch with an array as input could trigger an Error and the function may no get to the point where it checks if the sitemapUrl can be used with map.
Also take into account that map will call the function in every single element of the array and return an array with a result for each of element. So in your case B3:B6 would call the function for the value at B3, B4, B5 and B6 and return an array of length 4 with the result. For your case in which you want a single list you need to flattern the array afterwards
I would change your function to be like this:
function sitemaps(sitemapUrl) {
if (sitemapUrl.map) {
return sitemapUrl.map(sitemaps).flat();
} else {
var array = [];
var xml = UrlFetchApp.fetch(sitemapUrl).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement()
var sitemapNameSpace = XmlService.getNamespace("http://www.sitemaps.org/schemas/sitemap/0.9")
var urls = root.getChildren('url', sitemapNameSpace)
for (var i = 0; i < urls.length; i++) {
var loc = urls[i].getChild('loc', sitemapNameSpace).getText();
var lastmod = urls[i].getChild('lastmod', sitemapNameSpace).getText();
array.push([loc, lastmod]);
}
return array
}
}
Although what you are doing is fine take into account that it also exists a way to retrieve all the request at the same time (
UrlFetchApp.fetch()) but for this specific case you would need to flatten a reshape the input array.
I'm trying to make a 2D matrix dynamic system which identifies whether there is an "object" at X,Y coordinates (true), or not (false).
Simplified example code:
var coords = [[]]; // Matrix is over 10,000 x 10,000
var objectX = 76;
var objectY = 54;
coords[objectX][objectY] = true;
//Check to see if there is an object # coordinates
if(coords[100][65] == false || coords[100][65] === undefined)
{
//There is no object # 100 x 65
}
else
{
//Object detected # 100 x 65
}
But it seems I can't do it this way, since I think I have to start from [0][0], [0][1], [0][2], ... , ect; or something..
Also, matrix is too large to define via putting it in a loop. I can't have it loading for hours.
I won't mind keeping an array segment 'undefined', as I treat it as false in my code.
How can I accomplish this?
You need to make sure the first dimension array exists before you address the second dimension:
if (coords[objectX] === undefined) coords[objectX] = [];
coords[objectX][objectY] = true;
If upfront you know you actually need an element for each X,Y position (which will consume more memory), then initialise the matrix first with a loop:
for (var objectX=0; objectX <= maxX; objectX++) {
coords[objectX] = [];
for (var objectY=0; objectY <= maxY; objectY++) {
coords[objectX][objectY] = false;
}
}
Depending on your needs, you might get better memory usage and performance if you would use a different structure:
var coords = [];
coords[objectX * (maxX + 1) + objectY] = true;
Or if you do not know the range of X nor Y:
coords = {}; // object whose properties will be X,Y strings:
coords[objectX + ',' + objectY] = true;
I am trying to identify each drawing.
For example after I draw an object I want that object to have the propriety name = "My Drawing 1" so I can easily refer to it later by
canvas.getObjectByName('My Drawing Name');
getObjectByName function
fabric.Canvas.prototype.getItemByName = function(name) {
var object = null, objects = this.getObjects();
for (var i = 0, len = this.size(); i < len; i++) {
if (objects[i].name && objects[i].name === name) {
object = objects[i];
break;
}
}
return object;
};
The code that activates drawing function:
canvas.isDrawingMode = true;
var img = $("#patternImg")[0];
var texturePatternBrush = new fabric.PatternBrush(canvas);
texturePatternBrush.source = img;
texturePatternBrush.selectable = true;
texturePatternBrush.name = img.getAttribute("data-name");
canvas.freeDrawingBrush = texturePatternBrush;
canvas.freeDrawingBrush.width = img.getAttribute("data-height");
Using the code above I can check if can verify if a drawing exists by:
fabric.Canvas.prototype.getDrawByName = function(name) {
var object = null, objects = this.getObjects();
for (var i = 0, len = this.size(); i < len; i++) {
if (objects[i].canvas.freeDrawingBrush.name && objects[i].canvas.freeDrawingBrush.name === name) {
object = objects[i];
break;
}
}
return object;
};
The problem is each time I am drawing an object that has another name canvas.FreeDrawingBrush.name will be the same for each object on my canvas.
I am not so familiar with FabricJS and I don't even know if what I am trying to do is even possible. At least I made myself clear what I am trying to do ?
When accessing the canvas property of a fabric.Object, you are simply getting a reference to the fabric.Canvas element that this object is rendered on. The freeDrawingBrush property of this fabric.Canvas element will always be the current free drawing brush.
Instead, I would set this name property onto each individual object, when it is done drawing. (This could be when you exit from drawing mode, or perhaps right before you switch to a different brush) using fabric.Object.set method.
Doing it this way, you aren't relying on an object's canvas property in any way.
I have been struggling with this problem the entire day. I feel like it's super solvable, and I'm not sure where I'm going wrong. Each time I go to post this, I feel like I come up with a different solution that doesn't end up working.
I'm looking to do the following:
var someObj = {};
// #param key - string - in the form of "foo-bar-baz" or "foo-bar".
// (i won't know the number of segments ahead of time.)
// #param value - string - standard, don't need to act on it
function buildObject( key, value ) {
var allKeys = key.split("-");
// do stuff here to build someObj
}
Essentially the key will always take the format of key-key-key where i want to build someObj[key1][key2][key3] = value.
This JSFiddle contains a longer example with a sample layout of the data structure I want to walk away with.
Thanks so much for any help you can give.
var someObj = {};
// #param key - string - in the form of "foo-bar-baz" or "foo-bar".
// (i won't know the number of segments ahead of time.)
// #param value - string - standard, don't need to act on it
function buildObject( key, value ) {
var allKeys = key.split("-");
var container, i, n;
for (container = someObj, i = 0, n = allKeys.length; i < n - 1; ++i) {
var keyPart = allKeys[i];
container = Object.hasOwnProperty.call(container, keyPart)
? container[keyPart] : (container[keyPart] = {});
}
container[allKeys[n - 1]] = value;
}
I came up with http://jsfiddle.net/XAn4p/ before i saw Mike's answer. I'm posting just for another way.
var newObj = function ()
{};
newObj.prototype =
{
addToObject: function (keys, value)
{
var keySplit = keys.split("-",2);
if (keySplit.length > 1)
{
if(this[keySplit[0]] == null)
{
this[keySplit[0]] = new newObj();
}
var newKeys = keys.substr(keySplit[0].length +1);
this[keySplit[0]].addToObject(newKeys, value);
}
else
{
this[keySplit[0]] = value
}
}
};
var obj = new newObj();