KineticJS Setting a Variable Value On an Event - javascript

I define several kineticJS circles in an object and create and display several of those objects. What I want is to generate an XML object based on the ones the user selects out of the displayed circles.
For this I tried to set a variable value defined in the object when clicked on a particular circle and call it by an object.property kind of a way. However, this doesn't work.
Following is some of the code I used for the job:
function Graph(i, j, refRel, refRelTxt) {
subNodes = seventeen + eighteen + nineteen;
graphNode = "<" + refRelTxt + ">" + subNodes + "<" + refRelTxt + ">";
var layer = new Kinetic.Layer({
width: 200,
height: 100,
x: (stage.getWidth() / 2.5) + i,
y: (stage.getHeight() / 2.5) + j
});
var circle19 = new Kinetic.Circle({
x: 10,
y: layer.getHeight() / 2,
radius: cradius,
fill: '#CCCCCC'
});
//++++++++++++++++++++++++++++++++++++++++++++++++++
var circle18 = new Kinetic.Circle({
x: 10 + n,
y: (layer.getHeight() / 2) - m,
radius: cradius,
fill: '#CCCCCC'
});
var circle17 = new Kinetic.Circle({
x: 10 + n,
y: (layer.getHeight() / 2) + m,
radius: cradius,
fill: '#CCCCCC'
});
//============Mouse in/out operations
circle17.on('click', function (evt) {
this.setFill('#00FF00');
layer.draw();
seventeen = "<node>seventeen<node>";
});
circle18.on('click', function (evt) {
this.setFill('#00FF00');
layer.draw();
eighteen = "<node>eighteen<node>";
});
circle19.on('click', function (evt) {
this.setFill('#00FF00');
layer.draw();
nineteen = "<node>nineteen<node>";;
});
// add the shape to the layer
layer.add(circle19);
layer.add(circle18);
layer.add(circle17);
stage.add(layer);
}
Create some graph objects like the following:
var graph19 = new Graph(-(4*hdist), (0*vdist),"circle19","nineteen");
And then call the graph19.graphNode value to get the xml out based on the circles the user has clicked. However, graph19.graphNode doesn't get set with the values dynamically. I know I am doing something wrong here that I cannot figure out. When I set global variables and do this it works. What I want is to extract the xmls form the various Graph objects that are created.

If I understand correctly... you want to be able to call graph19.graphNode and it will output some pre-defined xml string that is dynamically populated depending on which circles the user clicked.
If so:
First off, to be able to call the property graphNode from a new Graph object, you have to assign this.graphNode instead of just graphNode by itself. Otherwise when you call graph19.graphNode it will be undefined.
Then you need to assign this to a variable like: var node = this; so that you can access node within the click function. (This is because by default, when you use this inside a Kinetic event function, click in this case, this will be assigned to the Kinetic.Shape you are binding the event to)
Finally, you need to update node (this.graphNode) every time you click a circle, use an array to keep track of the elements selected:
this.graphNode = '';
var node = this;
var nodeText = '';
circle17.on('click', function (evt) {
this.setFill('#00FF00');
layer.draw();
seventeen = "<node>seventeen<node>";
nodeText += seventeen;
node.graphNode = "<" + refRelTxt + ">" + nodeText + "<" + refRelTxt + ">";
});
circle18.on('click', function (evt) {
this.setFill('#00FF00');
layer.draw();
eighteen = "<node>eighteen<node>";
nodeText += eighteen;
node.graphNode = "<" + refRelTxt + ">" + nodeText + "<" + refRelTxt + ">";
});
circle19.on('click', function (evt) {
this.setFill('#00FF00');
layer.draw();
nineteen = "<node>nineteen<node>";
nodeText += nineteen;
node.graphNode = "<" + refRelTxt + ">" + nodeText + "<" + refRelTxt + ">";
});
The reason your code wasn't working was because you've defined
subNodes = seventeen + eighteen + nineteen;
Before seventeen eighteen and nineteen have even been defined (since they are defined when the user clicks on the the respective Kinetic.Circle
Also, as a suggestion I recommend that instead of creating a new Kinetic.Layer and adding it to the stage every time you call your Graph function, you might want to create a new Kinetic.Group instead and add that to the layer. See here for more information: What are the differences between group and layer in KineticJs
UPDATE
Okay if you need to deselect the objects as well, we'll need to keep track of which objects are selected in an array. Then we can use that array to determine how this.graphNode will be populated.
Something like this (note I haven't tested this code..):
this.graphNode = '';
this.selectedNodes = [];
this.nodeText = '';
var node = this;
circle17.on('click', function (evt) {
this.setFill('#00FF00');
layer.draw();
seventeen = "<node>seventeen<node>";
selectedNodes.push(seventeen);
node.nodeText = '';
for (var i=0; i<selectedNodes.length; i++) {
node.nodeText += selectedNodes[i];
}
node.graphNode = "<" + refRelTxt + ">" + node.nodeText + "<" + refRelTxt + ">";
});
circle18.on('click', function (evt) {
this.setFill('#00FF00');
layer.draw();
eighteen = "<node>eighteen<node>";
selectedNodes.push(eighteen);
node.nodeText = '';
for (var i=0; i<selectedNodes.length; i++) {
node.nodeText += selectedNodes[i];
}
node.graphNode = "<" + refRelTxt + ">" + node.nodeText + "<" + refRelTxt + ">";
});
circle19.on('click', function (evt) {
this.setFill('#00FF00');
layer.draw();
nineteen = "<node>nineteen<node>";
selectedNodes.push(nineteen);
node.nodeText = '';
for (var i=0; i<selectedNodes.length; i++) {
node.nodeText += selectedNodes[i];
}
node.graphNode = "<" + refRelTxt + ">" + node.nodeText + "<" + refRelTxt + ">";
});
After this you can do something similar to remove the object from the selectedNodes array on dblclick event.

Related

Current Alternative To .fontcolor() method in Javascript

I was given this task with some existing code to change the string color of each of three selector.value(s) that is output onto an input element to three different colors. The code boils the three selectors into a single output variable. Without destroying the code, I cannot figure out how to select each individual variables prior to condensing them.
If I could use the fontcolor() method, my life would be great but it's 2018 and I can't. Is there any way you can think of to solve this issue?To clarify, I need to alter the colors of the strings that belong to output(red), select1.value(blue) and select2.value(black.
Most of the action for this is happening in the parseOutput() function but I'm just stuck and don't think it's possible without rewriting the entire program.
function updateSelector(result){
var options = result.options;
var elementId = "select" + result.element;
var logger = document.getElementById('logger');
var selector = document.getElementById(elementId);
//logger.innerHTML = JSON.stringify(elementId);
selector.innerHTML = options;
selector.disabled = false;
}
google.script.run.withSuccessHandler(updateSelector).processOptions(0);
plate();
function resetAll(){
for (var i = 0;i<3;i++){
var selector = document.getElementById('select' + i);
selector.disabled = true;
selector.innerHTML = "";
}
google.script.run.withSuccessHandler(updateSelector).processOptions(0);
}
function finalSelection(){
var output = document.getElementById('out');
//output.focus();
output.select();
}
function plate(){
var plate = document.getElementById('plate');
plate.innerHTML = atob('Q3JhZnRlZCBieTogWmFjaGFyeSBTdGFjaG93aWFr');
}
//Adds the location as initial output, followed by divider, application, and issue if select1 is selected
//else statement added so if select0 is [Costco Website Name], to ommit the " - "
function parseOutput(){
var output = "";
if (select1.value.length > 0 && select0.value !== "[Costco Website Name]"){
output = output + ' - ' + select1.value + ' // ' + select2.value;
} else{
output = output + select1.value + ' // ' + select2.value;
}
out.value=output.trim();
}
And this is the Div that displays the output:
<div class="wide"><p><input class="wide" type="readonly" id="out" onfocus="this.select();"></p></div>
A modern replacement for fontcolor would use a span and a style (or class), e.g.:
function modernFontColor(str, color) {
return '<span style="color: ' + color + '">' + str + '</span>';
}
or
function modernFontClass(str, cls) {
return '<span class="' + cls + '">' + str + '</span>';
}
...where the class defines the styling.

How to write a dynamic html tag

I have this for-in loop that is supposed to return a div element with an img tag that has an onclick function. For some reason I get this error - Uncaught SyntaxError: missing ) after argument list - I have no idea where I missed it. Any help or advice will be much appreciated. Thank you.
for (var key in icons) {
var legend = document.getElementById('legend');
//the variables below points to objects
var type = icons[key];
var name_place = type.name;
var icon = type.icon;
var div = document.createElement('div');
div.innerHTML = '<img' + ' src="' + icon + '"' +
'onclick="displayMarker( ' + name_place + ' )"' + '> ' + name_place;
legend.appendChild(div);
}
//When I try:
div.innerHTML = '<img' + ' src="' + icon + '"' +
'onclick="displayMarker(name_place)"> ' + name_place;
the variable name_place is not passed into the function
var icons = {
one: {
name: 'name1',
icon: 'icon1.img'
},
two: {
name: 'name2',
icon: 'icon2.img'
}
};
function displayMarker( arg) {
console.log("displayMarker argument %s value: %s", typeof arg, arg);
}
for (var key in icons) {
var legend = document.getElementById('legend');
//the variables below points to objects
var type = icons[key];
var name_place = type.name;
var icon = type.icon;
var div = document.createElement('div');
div.innerHTML = '<img src="' + icon + '" onclick="displayMarker(\'' + name_place + '\')"> ' + name_place;
legend.appendChild(div);
}
<div id="legend"></div>
You need to put add the quotation marks for the parameter for the function parameter.
Since you are already using the single quote for string representation, you need to escape \' the characters for parameter passing.
Suggestion: Use event delegation if possible.

OpenLayers 4 - LayerFilter on forEachFeatureAtPixel

I have 2 vector layers of which I want only 1 to be selectable for a WFS get feature info layer. OL4 docs tell me there is an opt_layerfilter for the forEachFeatuerAtPixel function.
I’m in a similar situation like this: OpenLayers 3 hasFeatureAtPixel filter for layer.
Due to my lack of JavaScript knowledge I can’t seem to make it work with the following code in OpenLayers 4:
var displayFeatureInfo = function (pixel) {
var features = [];
map.forEachFeatureAtPixel(pixel, {
layerFilter: function (layer) {
return layer.get('name') === 'isochrones';
}
}, function (feature) {
features.push(feature);
});
if (features.length > 0) {
var info = [];
var i, ii;
for (i = 0, ii = features.length; i < ii; ++i) {
info.push('<div id="infobox">' + '<p2>' + 'Isochroon ' + features[i].get('name') + ', locatie ' + features[i].get('facilityid') + '</p2>' + '<p>' + 'aantal lopend: ' + features[i].get('n_pedestrians') + ', fiets: ' + features[i].get('n_bike') + ', ebike: ' + features[i].get('n_ebike') + '<br>' + 'speedpedelec: ' + features[i].get('n_speedpedelec') + ', auto: ' + features[i].get('n_car') + '</p>' + '</div>');
}
document.getElementById('info').innerHTML = info.join(', ') || '&nbsp';
} else {
document.getElementById('info').innerHTML = ' ';
}
};
map.on('click', function (evt) {
displayFeatureInfo(evt.pixel);
});
The layer I want to be selectable is named ‘isochrones’.
It throws me an error “d.call is not a function” when I try to click any vector layer in the map.
Could anyone point me in the right direction?
Looks like you have your args swapped.
The params for forEachFeatureAtPixel are (pixel, callback, options)
You have (pixel, options, callback)

JavaScript: Issues with methods and functions in refactored object

First time asking!
my refactored methods (methods used to be inside object) are not recognizing their relations to the object anymore... How do I get these to work?
I'm trying to apply a move and accelerate function to this object (car). The move_fn increases the car's position linearly (1, 2, 3, 4... n). The acc_fn increases the car's acceleration exponentially by adding the car's previous speed increase with its current position (30mph + 2 position = 32mph, 32mph + 3 position = 35mph, 35mph + 4 position = 39mph, etc.). Also, function_runner runs both methods simultaneously, which keeps everything commencing in order:
var move_fn = function(){
var prev_position = this.position
this.position += + 1
console.log(this.type + " is moving from " + prev_position + " to " +
this.position + '.')
}
var spd_fn = function(){
var prev_speed = this.speed
console.log(this.position)
this.speed += this.position
console.log(this.type + ' is accelerating from ' + prev_speed + ' to ' +
this.speed + '.' )
}
var function_runner = function(){
this.move_fn()
this.acc_fn()
}
var car = {
type: 'Honda CRV',
position: 1,
speed: 30,
move: move_fn,
speed: spd_fn,
fn_run: function_runner
}
car.function_runner()
Car no longer has a method called function_runner, you've assigned it to the fn_run method, so you'd call car.fn_run(). Same thing with move_fn - renamed to move, and "acc_fn" isn't defined anywhere.
So it'd be:
var move_fn = function(){
var prev_position = this.position
this.position += + 1
console.log(this.type + " is moving from " + prev_position + " to " +
this.position + '.')
}
var spd_fn = function(){
var prev_speed = this.speed
console.log(this.position)
this.speed += this.position
console.log(this.type + ' is accelerating from ' + prev_speed + ' to ' +
this.speed + '.' )
}
var function_runner = function(){
this.move()
this.speed()
}
var car = {
type: 'Honda CRV',
position: 1,
speed: 30,
move: move_fn,
speed: spd_fn,
fn_run: function_runner
}
car.fn_run()
...although it is a strange way of structuring it.

Javascript seemingly existing object

Unfortunately I can't easily paste the whole script that generates the variable, but I don't see it would be relevant either. Please instruct for more details, if necessary.
Javascript shows this:
console.log(gl.boxes);
shows:
[{element:{0:{jQuery19104057279333682955:9}, context:{jQuery19104057279333682955:9}, length:1}, boxName:"testi1", boxX:1, boxY:"180"}]
so gl.boxes[0] should exist, right? Still...
console.log(gl.boxes[0])
shows: undefined.
So what can I be missing here?
EDIT:
I will paste some more code about the generation of gl.boxes. Should be mostly about creating the variable as array first:
gl.boxes = [];
Then there is a function that handles creating and pushing new objects:
this.addBox = function (box) {
var retBox = {};
retBox.element = $(document.createElement('div'));
retBox.boxName = box.boxName;
retBox.boxX = box.boxX ? box.boxX : rootParent.defaultX;
retBox.boxY = box.boxY ? box.boxY : rootParent.defaultY;
retBox.element
.html(retBox.boxName)
.addClass(rootParent.boxClass)
.offset({ left: retBox.boxX, top: retBox.boxY })
.draggable({
stop: gl.URLs.dragStopDiv(retBox)
});
retBox.element.appendTo(rootParent.containerDiv);
gl.boxes.push(retBox);
return retBox;
};
The objects are created based on URL. Ie. in this test I have inline JS:
gl.objects.addBox({"boxName":"testi1","boxX":"50","boxY":"180"});
Only other place where the gl.boxes is being used is generating a URL based on the objects:
for(key in gl.boxes) {
var position = gl.boxes[key].element.position();
uri +=
"boxName["+key+"]="+gl.boxes[key].boxName+"&"+
"boxX["+key+"]="+position.left+"&"+
"boxY["+key+"]="+position.top+"&";
}
Maybe you need to change your loop to use indexes:
var i = 0,
position = {};
for (i = 0; i < gl.box.length; i += 1) {
position = gl.boxes[i].element.position();
uri += "boxName[" + i + "]=" + gl.boxes[i].boxName + "&" + "boxX[" + i + "]=" + position.left + "&" + "boxY[" + i + "]=" + position.top + "&";
}

Categories

Resources