Performing operations on substrings of text objects generated by D3 - d3.js

I'm wondering about having narrative text paragraphs scrolling down the side of a webpage while the user is progressing through data visualisation. As part of this it would be nice to add functionality to certain substrings of that text, for example to open a pop-up image it relates to. But I cannot think of any way to tell D3 to objectify substrings of text elements so they can respond to operators like mouseover.
Here's an example, plus jfiddle
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<title>Substring click</title>
<script type="text/javascript" src="scripts/d3.v3.js"></script>
</head>
<body>
<!-- example line -->
<p>The most interesting man in the world</p>
<div/>
<script type="text/javascript">
var link = "https://en.wikipedia.org/wiki/The_Most_Interesting_Man_in_the_World";
d3.select("body").selectAll("div").append("text").text("The most interesting man in the world");
// is there any way to make 'man' link to 'wiki_link' or perform some other operation?
</script>
</body>
</html>

Yes, it is possible, though you will need to format data in a way which is amenable to d3.
Demo
var data = [{ text: 'The most interesting ', href: false },
{ text: 'man', href: 'https://en.wikipedia.org/wiki/The_Most_Interesting_Man_in_the_World' },
{ text: ' in the world', href: false}];
var text = d3.select("body").selectAll("div").append("text");
text.selectAll('tspan')
.data(data)
.enter()
.append('tspan')
.html(function (d) {
return d.href
? '<a href=' + encodeURI(d.href) + '>' + d.text + '</a>'
: d.text;
});

Related

Why Firefox doesn't follow fragment identifiers in iframe?

Go to https://colnect.com/en/forum/app!/help/faq with Firefox, click any link and nothing happen.
Do the same in Chrome and you will be moved somewhere.
Is it Firefox issue or something else?
Code is:
The times are not correct!
<dl class="faq">
<dt id="f1r2"><strong>The times are not correct!</strong></dt>
<dd>It is possible the time displayed is from a ...</dd>
</dl>
UPD: simplified sample, there are 2 pages, page with iframe:
<!-- firefox-in-iframe.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Firefox in iframe</title>
</head>
<body>
<h1>Test TOC in Firefox</h1>
<iframe id="demo" src="firefox-in-iframe-w3.html" frameborder="1" style="width:100%; height:100%"></iframe>
</body>
</html>
and page with HMTL content from https://www.w3.org/TR/html401/struct/links.html with JavaScript added to align pages heights:
<script>
parent.document.getElementById('demo').addEventListener('load', (e) => {
e.target.style.height = Math.max(document.body.offsetHeight, document.body.scrollHeight) + 'px';
});
</script>
Here is old enough bug, its discussion and demo page mentioned there. Also one of the possible solutions are mentioned ibid. Сode could be like:
parent.document.getElementById('demo').addEventListener('load', (e) => {
// Align iframe and page heights. Iframe scrollbar can be hidden with CSS
e.target.style.height = Math.max(document.body.offsetHeight, document.body.scrollHeight) + 'px';
if (!(typeof InstallTrigger !== 'undefined')) return; // Not Firefox, do nothing
const iFrameOffset = e.target.offsetTop;
document.querySelectorAll('a[href^="#"]').forEach(el => {
const targetId = el.href.substring(el.href.indexOf('#') + 1);
el.addEventListener('click', () => {
const target = document.getElementById(targetId) || document.querySelector(`[name='${targetId}']`);
window.parent.scrollTo(0, iFrameOffset + target.offsetTop)
})
})
});

How to show the unhighlighted/ not selected data points on scatter plots when using brush/group in dc.js? And is multiple brushes possible in dc.js

I have two questions.
Is it possible to still show the not selected data in corresponding scatter plot. Where there can be two scatters around the selected data points that the other data points stay or if there can be a color.
Is it possible to have multiple brushes in dc.js. Where I can select one part of data and do that again on another place in the same scatter plot.
For question 1
This is before the selection:
This after selection on graph. I would still like the not selected one to still appear:
What I would like for question 1
Here is my code sample:
<!DOCTYPE html>
<html lang="en">
<head>
<title>dc.js - Scatter Plot Brushing Example</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../css/dc.css"/>
</head>
<body>
<div class="container">
<script type="text/javascript" src="header.js"></script>
<p>Brush on one chart to see the points filtered on the other.</p>
<div id="test1"></div>
<div id="test2"></div>
<script type="text/javascript" src="../js/d3.js"></script>
<script type="text/javascript" src="../js/crossfilter.js"></script>
<script type="text/javascript" src="../js/dc.js"></script>
<script type="text/javascript">
var chart1 = dc.scatterPlot("#test1");
var chart2 = dc.scatterPlot("#test2");
var data = "x,y,z\n" +
"1,1,3\n" +
"5,2,11\n" +
"13,13,13\n"+
"5,3,20\n"+
"12,12,10\n"+
"3,6,8\n"+
"15,2,9\n"+
"8,6,14\n"+
"1,4,9\n"+
"8,8,12\n";
var data = d3.csvParse(data);
data.forEach(function (x) {
x.x = +x.x;
x.y = +x.y;
x.z = +x.z;
});
var ndx = crossfilter(data),
dim1 = ndx.dimension(function (d) {
return [+d.x, +d.y];
}),
dim2 = ndx.dimension(function (d) {
return [+d.y, +d.z];
}),
group1 = dim1.group(),
group2 = dim2.group();
chart1.width(300)
.height(300)
.x(d3.scaleLinear().domain([0, 20]))
.yAxisLabel("y")
.xAxisLabel("x")
.clipPadding(10)
.dimension(dim1)
.excludedOpacity(0.5)
.group(group1);
chart2.width(300)
.height(300)
.x(d3.scaleLinear().domain([0, 20]))
.yAxisLabel("z")
.xAxisLabel("y")
.clipPadding(10)
.dimension(dim2)
.excludedColor('#ddd')
.group(group2);
dc.renderAll();
</script>
</div>
</body>
</html>
A1) That will be pretty difficult because dc.js sets the d of the paths of the not selected symbols in the other chart to d="M0,0". That means no path at all and all the symbols are now in the origin of the chart.
Edit
Looking at the code and after a little experiment I found if you add these then the other dots are visible
.emptySize(3)
.emptyOpacity(0.5)
The name is not very explanatory.

D3 Dimple - How to show multiple dimple charts on same page?

I'm making an html page with several examples of charts that I will be using. On the page I have a Dimple line graph, a pie chart, a wordcloud etc. When I try to add a second dimple graph - this time a bar graph, the first dimple line graph that I already have on the page is drawn on top of my bar graph:
My HTML file looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3 Graphs</title>
<link rel="stylesheet" type="text/css" href="_/base.css">
<link rel="stylesheet" type="text/css" href="_/c3CSS.css">
<script type="text/javascript" src="_/d3.min.js"></script>
<script type="text/javascript" src="_/dimple.v2.1.0.min.js"></script>
<script type="text/javascript" src="_/c3.min.js"></script>
<script type="text/javascript" src="_/d3.layout.cloud.js"></script>
</head>
<body>
<div id="chartContainer">
<h1>Hot Topics Line</h1>
<script type="text/javascript" src=CurvyLine.js></script>
</div>
<h1>Hot Topics Pie</h1>
<div id="chart">
<script type="text/javascript" src=Pie.js></script>
</div>
<div id="wordCloud">
<h1>Clickable Word Cloud</h1>
<script type="text/javascript" src=WordCloud.js></script>
</div>
<div id="bar">
<h1>Clickable Word Cloud</h1>
<script type="text/javascript" src=WeekBar.js></script>
</div>
</body>
</html>
Without adding the bar chart at the end, the line graph displays properly at the top of the page above the pie chart. However, with the bar chart added, both the line and bar graph are drawn inside the "bar" div. Can anyone help with this please? Here is my line graph js file:
var svg = dimple.newSvg("#chartContainer", 590, 400);
d3.tsv("data/tweet_example.tsv", function (data) {
//data = dimple.filterData(data, "Owner", ["Aperture", "Black Mesa"])
var myChart = new dimple.chart(svg, data);
myChart.setBounds(60, 30, 505, 305);
var x = myChart.addCategoryAxis("x", "Month");
x.addOrderRule("Date");
myChart.addMeasureAxis("y", "Tweets");
var s = myChart.addSeries("Topic", dimple.plot.line);
s.interpolation = "cardinal";
myChart.addLegend(60, 10, 500, 20, "right");
myChart.draw();
});
and here is my bar graph js file:
var svg = dimple.newSvg("#bar", 800, 410);
d3.tsv("data/tweet_example2.tsv", function (data) {
//data = dimple.filterData(data, "Owner", ["Aperture", "Black Mesa"])
var barChart = new dimple.chart(svg, data);
barChart.addCategoryAxis("x", ["Day", "Topic"]);
barChart.addMeasureAxis("y", "Tweets");
barChart.addSeries("Topic", dimple.plot.bar);
barChart.addLegend(65, 10, 510, 20, "right");
barChart.draw();
barChart.draw();
});
Your problem is that you are using the same global name svg to hold references to two different charts. When your second piece of code runs, it overwrites the svg value that you had from the first piece of code, and when the .tsv() callback returns, it finds a reference to the second graph.
Simplest solution: use different names for svg variable in both pieces of code: svg1 and svg2 will be fine.
Most elegant solution: use some kind of namespace management, such as wrapping both pieces of code in immediately called functions:
function() {
// your first chunk of code here
}()
function() {
// your second chunk of code here
}()
This way you will have two svg variables local to their own scopes

Cant Get D3 To Even Print Text

This is driving me nuts. Iv followed tutorials and I cant get this thing to do the simplest of actions.
Im just trying to get started. Iv got a skeleton page, a bare bones JSON file and the D3 V3 library loaded.
I can see from the inspector that everything loads fine. The JSON loads fine, but nothing happes. Im just trying to print some words into a few li elements, but i get nothing. I can see that the ul is appended to the page, but nothing else.
There's no JS errors, or anything to guide me. Just a blank page.
What am I doing wrong here?!
My Markup:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3</title>
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/main.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
<script src="js/vendor/d3.v3.min.js"></script>
<style>
path {
stroke: #fff;
fill-rule: evenodd;
}
</style>
<script>
function draw(data){
"use strict";
d3.select("body")
.append("ul")
.selectAll("li")
.data(data)
.enter()
.append("li")
.text(function(d) {
return 'Cant even see this message';
});
}
</script>
<script>d3.json("json/status.json", draw);</script>
</head>
<body>
</body>
</html>
and my JSON file
{
"status": "OK",
"name": "TEST A"
}
Your var data is not in correct format. D3.js assumes you will pass list to it but you provide an object. One simple fix to get you started would be to change status.json to:
[{
"status": "OK",
"name": "TEST A"
}]
From the API docs: https://github.com/mbostock/d3/wiki/Selections#wiki-data
selection.data([values[, key]])
Joins the specified array of data with the current selection. The
specified values is an array of data values, such as an array of
numbers or objects, or a function that returns an array of values.

Dynamically add tooltips to kendo grid rows of a column

I have a column with some notes displaying in the rows. Since the notes are huge, I have cut short the notes in the controller itself and sent that to my aspx page. What I want to achieve is, I want to display the complete notes in the form of a tool tip on mouse over of the grid row ( or if possible exactly on cell ). Is there any way to achieve this? Any help would be highly appreciated. Thanks in Advance.
Posting the answer as it might help anyone.
I got that working after doing this...
columns.Bound(p => p.partialNotes).Title("Description").HeaderHtmlAttributes(new { style = "text-align:center" }).HtmlAttributes(new { style = "text-align:left" }).Width("8%").HtmlAttributes(new { title = "#= completeNotes #" });
I have just added HtmlAttributes(new { title = "#= completeNotes #" })
So now when I place the mouse over the Description column data , I get the complete Notes as a tool tip.
Using a 3rd party widget is also a possibility. I've added qtip tips to column headers like this
KendoUI grid column array item
{
field:"property",
headerTemplate:kendo.template($("#h_Entity_property").html())
},
The header template
<link rel="stylesheet" type="text/css" href="lib/Craga89-qTip2-bfcc9ef/dist/jquery.qtip.min.css"/>
<link rel="stylesheet" type="text/css" href="lib/Craga89-qTip2-bfcc9ef/util/qtip.util.css"/>
<script type="text/javascript" src="lib/Craga89-qTip2-bfcc9ef/dist/jquery.qtip.min.js"></script>
<script type="text/javascript" src="lib/Craga89-qTip2-bfcc9ef/util/Dialogues.js"></script>
<script type="text/javascript" src="lib/Craga89-qTip2-bfcc9ef/util/Qtip2Util.js"></script>
<script type="text/x-kendo-template" id="h_Entity_property">
Property
<img onclick="Qtip.local(this, 'i_Entity_property')" src="img/info.gif"/>
<div id="i_Entity_property" style="display:none;">
Elaborate a bit...
</div>
</script>
Tooltip generator
var Qtip = {
local:function (element, contentId) {
$(element).qtip($.extend({}, qTipSharedOptions, {
content:{
text:$('#' + contentId).html(),
title:{
text:' ',
button:true
}
}
}
));
},
...
};
var qTipSharedOptions = {
position:{
at:'top right', // Position the tooltip above the link
my:'bottom left',
viewport:$(window), // Keep the tooltip on-screen at all times
effect:false // Disable positioning animation
},
style:{
classes:'ui-tooltip-tipsy ui-tooltip-shadow'
},
show:{
ready:true,
event:false,
solo:true // Only show one tooltip at a time
},
hide:false
};
you can do like below:
$("#Kendo-grid-div-id").kendoTooltip({
filter: "td:nth-child(2),td:nth-child(3)", //comma separated multiple columns
position: "bottom", //possible values: bottom,top,left,right,center
content: function(e){
var content = e.target.html();
return content;
}
}).data("kendoTooltip");

Resources