StackBlitz demo - stackblitz is flaky in chrome, may not show preview. I use edge with stackBlitz, also fine on chrome for mobile.
I've created this force directed graph that has multiple labels attached to paths that sit on a <line>.
The label turns blue when individually clicked. What I have tried to do net is change the appearance of the <line> style depending on which label has been clicked. Each label has its own data, so I use an attribute in the data to determine what style the line should be upon .on click. Demo line 292:
d3.select(this).each(function(d){
if (d.lineStyle === "Confirmed"){
_d3.select('.link').style('stroke', '#444');
_d3.select('.link').style('stroke-dasharray', '0');
} else if (d.lineStyle === "Unconfirmed"){
_d3.select('.link').style('stroke-dasharray', '8, 5');
}
});
If lineStyle equals "confirm" apply one style or if lineStyle equals "Unconfirmed" show another style.
The issue with the above is it only applies the style to one line regardless of what label you click.
I need to find the nearest line to the label and apply the style to that line only.
I tried using this.parentNode something like _d3.select(this.parentNode).selectAll('.link').style('stroke-dasharray', '8, 5');
Is there a way I can find the nearest .link class in relation to the label maybe?
I have also seen a way to build a relationship function and call that somehow.
Firstly, that each inside the listener is unnecessary, since you have just one element being clicked.
The problem is that d3.select('.link') will simply select the first .link it finds on the page, top to down. So, the behaviour you have is expected.
What you probably want is filtering a line according to the text clicked. That could be done with parentNode, nextSibling etc., but that's not possible due to the structure you created. Thus, you can do it based on data:
const thisLine = linkEnter.filter(e => e.index === d.index);
Then:
if (d.lineStyle === "Confirmed"){
thisLine.style('stroke', '#444');
thisLine.style('stroke-dasharray', '0');
} else if (d.lineStyle === "Unconfirmed"){
thisLine.style('stroke-dasharray', '8, 5');
};
There's nothing in your code to revert the change, but that's trivial to do.
Here is the forked code: https://stackblitz.com/edit/github-dzry6q-6vj5yx?file=src%2Fapp%2Fdirected-graph-experiment.service.ts,src%2Fapp%2Fapp.component.ts
Related
Here is the code: http://jsfiddle.net/celiostat/NCPv9/
the 2 Jquery plugin enables to change (and set):
- background color of div to gray
- text color to red.
Problem is I have to exactly point the mouse exactly ON the text so that text changes color too.
I would like to change background Div color AND text by clicking -- anywhere -- in the div
Tried various combination from other post..but nothing worked.
(ideally I would also like to change picture at the same time !)
$(".item_unselected").on("click", function() {
$(this).toggleClass("gray_cliked_box");
$(".item_unselected").not(this).removeClass("gray_cliked_box");
});
$(".item_text_in_menubar").on("click", function() {
$(this).toggleClass("blue_cliked_text");
$(".item_text_in_menubar").not(this).removeClass("blue_cliked_text");
});
You're fairly close, but the reason you have to click on the text is because you're only setting the class for the text once you click on it - you never set it from when you click on the div. Thankfully, you can optimize (and fix) your code by only having one event. If you click on a div, you simply set both items.
You can do this using the find method in jQuery to find the span that you want to modify when clicking on the div. The updated JS is as follows:
$(".item_unselected").on("click", function () {
$(".item_unselected").removeClass("gray_cliked_box");
$(".item_text_in_menubar").removeClass("blue_cliked_text");
var $this = $(this);
$this.addClass("gray_cliked_box");
$this.find(".item_text_in_menubar").addClass("blue_cliked_text");
});
Updated Fiddle: http://jsfiddle.net/NCPv9/3/
What this actually does, is remove the class from all the objects, and then just simply add the classes back to the ones you want. You also don't have to use toggleClass. You know you're adding it so just use addClass.
This is a CSS problem, not a jquery problem. I updated your last CSS selector to:
.gray_cliked_box .item_text_in_menubar { /*for jquery*/
color: red;
}
and the text changes to red when clicked.
The added selector says that children of .gray_clicked_box with a class .item_text_in_menubar should be red. This supercedes other definitions of .item_text_in_menubar because it's a more specific selector.
http://jsfiddle.net/NCPv9/4/
I am having items painted using d3 on browser. I want to highlight some of them depending on their property. For example, I have groceries, soaps in which soap elements will have type as [for_bath (OR) for_cloth_wash]. I want to select those elements specific to for_bath in all soaps and groceries combined and painted together on same screen.
How ?
Also, my another doubt is document.getElementById() is not working inside d3's selections code. Am I true or an oversight ?
EDIT
var data = {"soaps":{"lux":"bath", "cinthol":"bath", "rin","cloth_washing"},
"shoes":{"valentine":"teens", "bootie":"kids", "kuuch":"kids"}};
// Now I want to show all bath soaps highlighted, may be with a circle around them.
var svg = d3.select("svg")
.selectAll(".items")
.data(data).enter()
.append("circle")
// highlighting styles
;
Here I want to select bath soaps and round them up.
You haven't given us any code, so I'm going to guess here. What you're probably looking for are CSS attribute selectors. So if you want to select elements which have the attribute soap set to for_bath, you would do
d3.selectAll("[soap=for_bath]");
This is for DOM elements only. If you're talking about data elements, then you can use the .filter() method:
data.filter(function(d) { return d.soap == "for_bath"; });
Regarding your second question, I'm not sure what you mean. The arguments to d3.select() or d3.selectAll() are DOM selectors, so document.getElementById() doesn't make sense here. You can however certainly use it other functions:
d3.selectAll("something").each(function() {
d3.select(this); // the current element
document.getElementById("something"); // another element
});
I was wanting to have a javascript (jQuery) function that removed everything that didn't have the safe class.
The problem is, if the parent element is hidden, it cannot show the 'safe' part of it.
Is there a simple way to get around this? I'd rather not go in and span all of the elements that need removed.
trimmer = function(element){
x = $(element+' *:not(.safe)');
x.hide();
}
trimmer('section');
Fiddle
var element = 'section';
//finds all non `.safe` elements in `section`s and hides them
$(':not(.safe)', element).hide();
//finds all `.safe` elements in `section`s and shows the `section`s
$('.safe', element).parents(element).show();
Horen was right, it is indeed impossible to show parts of a hidden element.
To make only parts of the text disappear, the non-safe content must be labeled for removal.
$(element).contents().each(function() {
if (this.nodeType == 3)
$(this).wrap('<span class="disappear" />');
});
You can read more about this answer here:
How to add spans to all areas of a node that isn't restricted
I'm not even sure I'm asking or going about this the right way but it's probably easier if I just show it. Basically, I'm trying to have run an attr of each div as a parameter through a function and have it return a different result based on that div's attr.
The example, as you can see, is a group of dropdowns that appear when you click on a link in the container div. If you make a selection it saves that as a attr in the parent div. The problem arises when you click out, then back in on the container ... instead of reshowing each dropdown with the appropriate default or selection showing, it just mirrors the result of the a next to it.
http://jsfiddle.net/nosfan1019/b7F6x/5/
TIA
I inserted some console.log() statements to see what was happening with your various jQuery selectors. I observe the following:
when I click in the first "click" node, _container is "top one"
thus in your iteration of the three divs, you select both divs with class 'dd' contained in the div with class 'top one'
the parameters _attr and _parent that you pass to your function select() are the same for each node that is processed, giving the same result for both 'dd' boxes.
I think you want to change the selectors you use to locate the nodes to modify.
foo = foo.find('.dropdown-toggle').html(_new + '<b class="caret"></b>');
with this line you get two divs and hence you've change both values(in case the value was chosen from the droplist).
To restore selected values correctly:
function modified(_select) {
console.log("modify");
foo = $('#box').html();
foo = $(_select).html(foo);
// iterate on collection to restore selected value from selection tag;
foo.filter("div[selection]").each(function(i, v){
var selected = $(v).attr('selection');
$(v).find('.dropdown-toggle').html(selected + '<b class="caret"></b>');
});
}
Then, it's needed to be checked if any of parentDiv has [selection] attr:
if($(y).filter("div[selection]").length > 0){
return modified(y);
}
http://jsfiddle.net/b7F6x/50/
I have this javascript code that creates a slider:
http://jsfiddle.net/samccone/ZMkkd/
Now, i want to use this code on a checkbox input. the problem is that the code creates a child element that slides in it's parent using a css position, and an input cannot have a child.
My idea was to use background-position and just slide the background of the input from left to right using css instead of using real positioning.
How can I adapt this script? It is quite easy I think but after a couple of tries I just gave up, i'm not good enough :).
Thanks for your help,
Christopher
Believe it or not, for checkboxes a switch effect is possible to create without JavaScript.
If you follow your checkbox with a label:
<input type="checkbox" id="jim" />
<label for="jim"></label>
You will find that you can select the label with the next sibling selector:
input + label { /* some CSS */ }
Why is that useful? Because using the pseudo selector :checked you can now style the label based on the state of the checkbox:
input + label { background-position: 0 0; }
input:checked + label { background-position: 100% 0; }
Clearly, due to the for="jim" attribute, clicking on the label will change the state of the checkbox. So if you hide the checkbox, you end up with a styled, clickable label.
input { display: none; }
Of course, labels can have children so you can be as fancy as you want with your recreation of a switch. And you should be careful to include :focus styles as well, for people who tab to your checkbox rather than click on it.
For browsers that do not support the :checked pseudo class (IE8 and below), it's pretty easy to emulate with a global handler and a 'checked' class. Something like:
jQuery(document).bind('change', function(e){
var elem = jQuery(e.target);
// If this is not a checkox, do nothing.
if (elem.attr('type') !== 'checkbox') { return; }
// Add or remove checked class based on current state.
if (elem.attr('checked')) { elem.removeClass('checked'); }
else { elem.addClass('checked'); }
});
...should do it.
You might need to store some data in object properties (or the .data() api), but your background position idea should work just fine. Just replace your calls to .offset().left with .css('background-position') (you'll have to split and parseInt the string it returns tho) and keep plugin' away at it.