If you open this link in Chrome and hover on legends, it works fine. But if you open the same link in Firefox, something weird happens and line chart is not highlighting properly. In my personal code, I tried to explicitly add highlight class to the hovered line using the code
for (var i = 0; i < subchartIds.length; i++) {
if (subchartIds[i] === highlightedId) {
var el = chartObject.select('g.sub._' + subchartIds[i] + ' .chart-body .stack-list')._groups[0][0].childNodes[0].childNodes[0];
el.className.animVal += ' highlight';
el.className.baseVal += ' highlight';
} else {
chartObject.select('g.sub._' + subchartIds[i]).style("opacity", function () {
return 0.2;
});
}
}
where subchartIds array have IDs of number of line charts in my composite chart and highlightedId contains the ID of line chart I want to highlight i.e. line chart belonging to legend on which mouse is hovered.
After spending much time on it, I was able to solve it by first removing all the default properties which were set on path element, then reassigning required attributes myself.
for (var i = 0; i < subchartIds.length; i++) {
chartObject.select('g.sub._' + subchartIds[i]).style("opacity", function () {
return 1;
});
var localElement = chartObject.select('g.sub._' + subchartIds[i] + ' .chart-body .stack-list')._groups[0][0].childNodes[0].childNodes[0];
localElement.className.animVal = localElement.className.animVal.replace('highlight','');
localElement.className.baseVal = localElement.className.baseVal.replace('highlight','');
localElement.className.animVal = localElement.className.animVal.replace('fadeout','');
localElement.className.baseVal = localElement.className.baseVal.replace('fadeout','');
}
for (var i = 0; i < subchartIds.length; i++) {
if (subchartIds[i] === highlightedId) {
var elementToHighlight = chartObject.select('g.sub._' + subchartIds[i] + ' .chart-body .stack-list')._groups[0][0].childNodes[0].childNodes[0];
elementToHighlight.className.animVal += ' highlight';
elementToHighlight.className.baseVal += ' highlight';
chartObject.select('g.sub._' + subchartIds[i]).style("opacity", function () {
return 0.9;
});
} else {
var elementToFade = chartObject.select('g.sub._' + subchartIds[i] + ' .chart-body .stack-list')._groups[0][0].childNodes[0].childNodes[0];
elementToFade.className.animVal += ' fadeout';
elementToFade.className.baseVal += ' fadeout';
chartObject.select('g.sub._' + subchartIds[i]).style("opacity", function () {
return 0.2;
});
}
}
Related
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(', ') || ' ';
} 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)
This code displays the content of JSON file by formatting every word into sentences and then into HTML. On mouseover, words become blue. On click they become red. The next thing I want to do is to display the translation of the words (already in the json array) onclick.
https://jsfiddle.net/ve64qvtm/
var json = [
[
["Peki", "Well"],
["nedir", "what"],
["bu", "it"],
...
]
];
var arr2 = [];
for (k = 0; k < json.length; k++) {
var arr = json[k];
arr2.push('<p>');
for (i = 0; i < arr.length; i++) {
if (arr[i][0].length == 1) {
arr2.push(arr[i][0]);
} else {
arr2.push(' <span class="notclicked word ' + i + '">' + arr[i][0] + '</span>');
}
}
arr2.push('</p>');
}
document.getElementById("text").innerHTML = arr2.join('');
var words = [...document.getElementsByClassName("word")];
words.forEach(function(word) {
word.onclick = function() {
if (word.className == "clicked") {
word.className = 'notclicked';
}
if (word.className == "onmouse") {
word.className = 'clicked';
}
}
word.onmouseover = function onMouse() {
if (word.className != "clicked") {
word.className = 'onmouse';
}
}
word.onmouseout = function onMouse() {
if (word.className != "clicked") {
word.className = 'notclicked';
}
}
});
I have no idea how to do this as the text to display is a variable.
How am I supposed to do this?
How about using Twitter Bootstraps tooltip. Add jQuery, bootstraps JS and CSS; once all this is added you would need to edit the line
arr2.push(' <span class="notclicked word ' + i + '">' + arr[i][0] + '</span>');
To something like
arr2.push(' <span class="notclicked word ' + i + '" data-toggle='tooltip' data-placement='top' title='YOUR_TRANSLATION_HERE'>' + arr[i][0] + '</span>');
EDIT 2 - Updated Link:
Here is a working example
Edit 3
I Would also add a bit of margin on top and bottom so that you don´t get unexpected behaviour from the tooltips, just because there is no space.
I have an application using firebase which looks like this:
The tick boxes to the right hand side of each 'Book', when clicked, sends the value of the firebase object into a string as shown below:
When clicking these tick boxes, I would like the style of the box and content to change so they turn blue. I have added this piece of code into the on click event:
function select(data, book, key) {
//What I added
document.getElementById('selectBook').style.color="blue";
document.getElementById('selectBook').style.borderColor="blue";
//
var selectBookRef = book;
document.getElementById('alltext').value += selectBookRef + ',';
}
However, this only turns the first box blue. No matter which check box I click, the first one just changes to blue and the rest stay grey.
Here is the JS code which creates the checkbox icons and the JS to highlight the selected check boxes.
function refreshUI(list) {
var lis = '';
var lis2 = '';
var lis3 = '';
//This generates the 3 columns on the application page
for (var i = 0; i < 10 && i < list.length; i++) {
lis += '<li style="width: 150px" data-key="' + list[i].key + '">' + list[i].book + genLinks(list[i].key, list[i].book) +'</li>';
};
for (var i = 10; i < 20 && i < list.length; i++) {
lis2 += '<li style="width: 150px" data-key="' + list[i].key + '">' + list[i].book + genLinks(list[i].key, list[i].book) +'</li>';
};
for (var i = 20; i < 30 && i < list.length; i++) {
lis3 += '<li style="width: 150px" data-key="' + list[i].key + '">' + list[i].book + genLinks(list[i].key, list[i].book) +'</li>';
};
document.getElementById('bookList').innerHTML = lis;
document.getElementById('bookList2').innerHTML = lis2;
document.getElementById('bookList3').innerHTML = lis3;
};
//This creates the 3 icons of delete, clear and select.
function genLinks(key, bkName) {
var links = '';
links += '<i id="deleteBook" class="material-icons">delete</i> ';
links += '<i id="removeBook" class="material-icons">clear</i> ';
links += '<i id="selectBook" onclick="functionSelected()" class="material-icons">check</i>';
return links;
};
function del(key, bkName) {
var deleteBookRef = buildEndPoint(key);
deleteBookRef.remove();
}
//This is the function to select and insert the data into the string as well as highlight each checkbox
function select(data, book, key) {
document.getElementById('selectBook').style.color="blue";
document.getElementById('selectBook').style.borderColor="blue";
var selectBookRef = book;
document.getElementById('alltext').value += selectBookRef + ',';
}
function buildEndPoint (key) {
return new Firebase('https://project04-167712.firebaseio.com/books/' + key);
}
bookList.on("value", function(snapshot) {
var data = snapshot.val();
var list = [];
for (var key in data) {
if (data.hasOwnProperty(key)) {
book = data[key].book ? data[key].book : '';
if (book.trim().length > 0) {
list.push({
book: book,
key: key
})
}
}
}
refreshUI(list);
});
If anybody can help it will be much appreciated.
Thanks,
G
The only thing I can see is that you are using the same id tags for multiple different objects on the same page. If you use it at more than one place, use a class! You should never have more than one of the same id because you will be facing a lot of repeating problems..
UPDATE:
I changed my script to this and it works. Way simpler and it works.
function myFunction(valor) {
var elementos = document.getElementsByClassName("inner");
var i;
for (i = 1; i < elementos.length+1; i++) {
document.getElementById("age"+i).style.visibility = "hidden";
}
document.getElementById("age"+valor).style.visibility = "visible";
}
I have this script:
function myFunction(valor) {
alert("Has seleccionado " + valor);
var elementos = document.getElementsByClassName("inner");
//alert ("Tienes " + elementos.length + " elementos.");
var i;
for (i = 1; i < elementos.length + 1; i++) {
var sty = document.getElementById("age" + i);
//alert("age"+i);
if (getComputedStyle(sty).getPropertyValue("visibility") == "hidden") {
document.getElementById("age" + valor).style.visibility = "visible";
} else {
document.getElementById("age" + i).style.visibility = "hidden";
}
}
}
That I control with a slider control. What I'm doing is hiding or showing some divs with depending of what I choose from the slider.
This is how I paint my data before trying to hide or shsow elements with the slider:
$(window).load(function() {
$.getJSON('http://xxxxx/xxxxx.json', function(data) {
var output = "<ul class='lista'><div class='outer'>";
for (var i in data.lbclassic) {
output += "<div style='visibility:hidden;' class='inner'id=" + "age" + data.lbclassic[i].ageinweeks + ">" + "<p>" + data.lbclassic[i].ageinweeks + "--" + data.lbclassic[i].cumul + "--" + data.lbclassic[i].perhh + "--" + data.lbclassic[i].perhd + "--" + data.lbclassic[i].eggweightinweek + "--" + data.lbclassic[i].eggmasscumul1 + "--" + data.lbclassic[i].eggmassinweek + "--" + data.lbclassic[i].eggmasscumul + "</p></div>";
}
output += "</div></ul>";
document.getElementById("placeholder").innerHTML = output;
});
});
This works great until one point - once I get to the last element (90 in this case), it won't show up.
Isn't it more easy to use the css "display:none;" feature for hidding your element.
.yourclass{
display:none;
}
just edit the class with js
Link to CSS
function myFunction(valor) {
var elementos = document.getElementsByClassName("inner");
var i;
for (i = 1; i < elementos.length+1; i++) {
document.getElementById("age"+i).style.visibility = "hidden";
}
document.getElementById("age"+valor).style.visibility = "visible";
}
I've been doing web development for quite sometime and have never seen this behavior with JavaScript. This is the code I started out with:
function processLogin() {
if (loginReq.readyState == 4) {
var data = eval('(' + loginReq.responseText + ')');
data = data.userData;
var focus = data.team.focus.coordinates;
thisTeam = new Team(data.team.id, data.team.missionId, data.team.name, data.team.operatingArea.coordinates[0]);
if (data.team.zoomLevel != '') {
thisTeam.zoomLevel = data.team.zoomLevel;
}
if (focus.length > 0) {
thisTeam.focusLat = focus[1];
thisTeam.focusLon = focus[0];
}
for (var i = 0; i < data.teams.length; i++) {
var temp_team = new Team(data.teams[i].id, data.teams[i].missionId, data.teams[i].name, []);
teams.push(temp_team);
}
var teamDropDownText = [];
for (var j = 0; j < teams.length; j++) {
if (thisTeam.teamId == teams[j].teamId) {
teamDropDownText.push('<option value="' + teams[j].teamId + '" selected="selected">' + teams[j].name + '</option>');
} else {
teamDropDownText.push('<option value="' + teams[j].teamId + '">' + teams[j].name + '</option>');
}
}
$('#addIncidentTeam').html(teamDropDownText.join(''));
$('#editIncidentTeam').html(teamDropDownText.join(''));
// When all this has finished, make the
// rest of the calls to get the rest of the data
startTimer();
downloadDevices();
initializeMap();
}
}
What I have written there isn't that important, and let me explain why.
The line with the single semicolon after thisTeam.zoomLevel = data.team.zoomLevel; was giving me a syntax error in firebug. I read and re-read my code, and couldn't figure out what I did wrong, so I put the semicolon on the same line as thisTeam.zoomLevel = data.team.zoomLevel and it told me it had a syntax error on the blank line!
To do another test, I moved this whole function to it's own JavaScript file and put everything after that line on one line and even tried to condense some of the code above, so now it looks like this:
function processLogin() {
if (loginReq.readyState == 4) {
var data = eval('(' + loginReq.responseText + ')');
data = data.userData;
var focus = data.team.focus.coordinates;
thisTeam = new Team(data.team.id, data.team.missionId, data.team.name, data.team.operatingArea.coordinates[0]); if (data.team.zoomLevel.length > 0) { thisTeam.zoomLevel = data.team.zoomLevel; } if (focus.length > 0) { thisTeam.focusLat = focus[1];thisTeam.focusLon = focus[0];} for (var i = 0; i < data.teams.length; i++) { var temp_team = new Team(data.teams[i].id, data.teams[i].missionId, data.teams[i].name, []); teams.push(temp_team); } var teamDropDownText = []; for (var j = 0; j < teams.length; j++) { if (thisTeam.teamId == teams[j].teamId) { teamDropDownText.push('<option value="' + teams[j].teamId + '" selected="selected">' + teams[j].name + '</option>'); } else { teamDropDownText.push('<option value="' + teams[j].teamId + '">' + teams[j].name + '</option>'); } } $('#addIncidentTeam').html(teamDropDownText.join('')); $('#editIncidentTeam').html(teamDropDownText.join('')); /* When all this has finished, make the rest of the calls to get the rest of the data */ startTimer(); downloadDevices(); initializeMap(); var kmlLink = document.getElementById('kmlLink'); var geoserverLink = document.getElementById('geoserverLink') if (user_role.substring(0, 1) == 'M') { kmlLink.href = "https://www.intelink.gov/giatstldni/hermes/webservice/kml/download/M&" + thisTeam.missionId + "&48"; kmlLink.innerHTML = "https://www.intelink.gov/giatstldni/hermes/webservice/kml/download/M&" + thisTeam.missionId + "&48"; geoserverLink.href = "https://www.intelink.gov/giatstldni/geoserver/wms/kml?layers=hermes_all&cql_filter=mission_id+=+" + thisTeam.missionId; geoserverLink.innerHTML = "https://www.intelink.gov/giatstldni/geoserver/wms/kml?layers=hermes_all&cql_filter=mission_id+=+" + thisTeam.missionId;} else { kmlLink.href = "https://www.intelink.gov/giatstldni/hermes/webservice/kml/download/T&" + thisTeam.id + "&48"; kmlLink.innerHTML = "https://www.intelink.gov/giatstldni/hermes/webservice/kml/download/T&" + thisTeam.id + "&48"; geoserverLink.href = "https://www.intelink.gov/giatstldni/geoserver/wms/kml?layers=hermes_all&cql_filter=team_id+=+" + thisTeam.id; geoserverLink.innerHTML = "https://www.intelink.gov/giatstldni/geoserver/wms/kml?layers=hermes_all&cql_filter=team_id+=+" + thisTeam.id; } } }
I did this just to see what error I would get, I knew it wouldn't work correctly. But now it's telling me there's an error on a line that doesn't exist in the file! I get:
syntax error
[Break On This Error] (10 out of range 8)
I went and commented more code out and it just made it 10 out of range 6! I don't understand!
I found the culprit. One of the values of the JSON returned was empty (no quotes or anything). Not a very helpful error message.