d3js,vuejs, select a subtree - d3.js

i am a beginner in the JS, Vue and D3 programming but already managed to understand the basics, i think :).
So currently i am trying to implement a program which renders a phylogenetical tree using Vue.js and D3.js. Using this example as a start up:
https://bl.ocks.org/lorenzopub/02ccce43d708919ca7c0b242fe1c93f2
So far i managed to get my program to open a tree file and to render it properly. Also i can select certain nodes and change their color accordingly. But my problem now is how to select a subtree and change the color of the children nodes.
Any help and or hints will be appreciated!
Thank you!
Here is my code so far:
<!DOCTYPE html>
<head>
<script type="text/javascript" src="VUE/vue.min.js"></script>
<script type="text/javascript" src="D3/d3.js"></script>
<script>function parseNewick(s) {
var ancestors = [];
var tree = {};
var tokens = s.split(/\s*(;|\(|\)|,|:)\s*/);
for (var i=0; i<tokens.length; i++) {
var token = tokens[i];
switch (token) {
case '(': // new branchset
var subtree = {};
tree.branchset = [subtree];
ancestors.push(tree);
tree = subtree;
break;
case ',': // another branch
var subtree = {};
ancestors[ancestors.length-1].branchset.push(subtree);
tree = subtree;
break;
case ')': // optional name next
tree = ancestors.pop();
break;
case ':': // optional length next
break;
default:
var x = tokens[i-1];
if (x == ')' || x == '(' || x == ',') {
tree.name = token;
} else if (x == ':') {
tree.length = parseFloat(token);
}
}
}
return tree;
};
</script>
<style>
.node {
opacity: 1;
}
.node circle {
fill: #999;
cursor: pointer;
}
.node text {
font: 12px sans-serif;
cursor: pointer;
}
.node--internal circle {
fill: #555;
}
.node--leaf circle {
fill: blue;
}
.node--selected circle {
fill: blue
}
.node--internal text {
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
stroke-dasharray: 1000;
}
.node:hover {
pointer-events: all;
stroke: #ff0000;
}
.node.highlight {
fill: red;
}
.controls {
position: fixed;
top: 16px;
left: 16px;
background: #f8f8f8;
padding: 0.5rem;
display: flex;
flex-direction: column;
}
.controls > * + * {
margin-top: 1rem;
}
label {
display: block;
}
.list-enter-active, .list-leave-active {
transition: all 1s;
}
.list-enter, .list-leave-to /* .list-leave-active for <2.1.8 */ {
opacity: 0;
transform: translateY(30px);
}
.line-enter-active, .line-leave-active {
transition: all 2s;
stroke-dashoffset: 0;
}
.line-enter, .line-leave-to /* .list-leave-active for <2.1.8 */ {
stroke-dashoffset: 1000;
}
</style>
</head>
<body>
<div id="app">
<div class='controls'>
<input type="file" #change="onFileChange">
<label>Search...</label>
<input type="text" v-model="search" />
</div>
<svg v-bind:width="settings.width" v-bind:height="settings.height">
<!-- LINKS BETWEEN NODES -->
<transition-group tag="g" name="line">
<g v-for="link in links" v-bind:key="link.id">
<path class="link" v-bind:style="link.style" v-bind:d="link.d"></path>
</g>
</transition-group>
<!-- LINKS BETWEEN NODES -->
<transition-group tag="g" name="list">
<g class="node" v-on:dblclick="selectSubTree(node,index)" v-on:mouseover="mouseOver(node,index)" v-on:click="select(node,index)" v-for="(node, index) in nodes" v-bind:key="node.id" v-bind:style="node.style" v-bind:class="[node.className, {'highlight': node.highlight}]">
<!-- Circles for each node -->
<circle v-bind:r="node.r" v-bind:style="node.selCol"></circle>
<!-- Finally, text labels -->
<text v-bind:dx="node.textpos.x" v-bind:dy="node.textpos.y" v-bind:style="node.textStyle">{{ node.text }}</text>
</g>
</transition-group>
</svg>
</div>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: function (){
return {
treeFile: '',
search: '',
selected: [],
settings: {
strokeColor: "#19B5FF",
width: 1000,
height: 1000
}
}
},
computed: {
root: function(){
var vm = this;
if(vm.treeFile){
return vm.tree(
d3.hierarchy(parseNewick(vm.treeFile),function(d) { return d.branchset; })
.sum(function(d) { return d.branchset ? 0 : 1; })
.sort(function(a, b) { return (a.value - b.value) || d3.ascending(a.data.length, b.data.length); }));
}
},
tree: function(){
return d3.tree().size([this.settings.height, this.settings.width - 160]);
},
nodes: function(){
var vm = this;
if(this.root){
return vm.root.descendants().map(function(d,i) {
vm.selected[i]=0;
return{
id: d.data.name,
index: i,
r: 7,
className: "node" + (d.children ? " node--internal" : " node--leaf"),
text: d.data.name.substring(d.data.name.lastIndexOf(".") +1),
highlight: d.data.name.toLowerCase().indexOf(vm.search.toLowerCase()) != -1 && vm.search != "",
style: {
transform: "translate(" + d.y + "px," + d.x + "px)",
},
textpos: {
x: d.children ? -10 : 10,
y: 3
},
textStyle: {
textAnchor: d.children ? "end" : "start"
},
children: d.children,
selCol: {fill: '#bfbfbf'}
};
});
}
},
links: function() {
var vm = this;
if (vm.root) {
// here we'll calculate the "d" attribute for each path that is then used in the template where we use "v-for" to loop through all of the links to create <path> elements
return vm.root.descendants().slice(1).map(function(d) {
return {
id: d.data.name,
d: "M" + d.y + "," + d.x + "C" + (d.parent.y + 100) + "," + d.x + " " + (d.parent.y + 100) + "," + d.parent.x + " " + d.parent.y + "," + d.parent.x,
// here we could of course calculate colors depending on data but for now all links share the same color from the settings object that we can manipulate using UI controls and v-model
style: {
stroke: vm.settings.strokeColor
}
};
});
}
}
},
methods: {
onFileChange(e) {
var file = e.target.files[0];
var reader = new FileReader();
var vm = this;
reader.onloadend = function(e) {
vm.treeFile = e.target.result;
};
reader.readAsText(file);
},
select: function(node, index) {
var vm = this;
if(this.selected[index] == 0){
this.selected[index]=1;
vm.nodes[index].selCol='fill: green';
}else{
this.selected[index]=0;
vm.nodes[index].selCol='fill: #bfbfbf';
}
vm.$forceUpdate();
},
mouseOver: function (node,index){
// console.log(node.id + " " + node.isSelected);
},
selectSubTree: function(node,index){
var vm=this;
if(this.selected[index] == 0){
this.selected[index]=1;
vm.nodes[index].selCol='fill: green';
}else{
this.selected[index]=0;
vm.nodes[index].selCol='fill: #bfbfbf';
}
if(node.children){
// console.log(node.id + " HAVE CHILDREN");
// console.log("NC: " + node.children);
node.children.forEach(function (d,i){
// this.selected=i;
vm.selected[i]=1;
vm.nodes[index].selCol='fill: green';
console.log("SELECTING: " + d.data.name + " " + i);
console.log(vm.$refs.A);
// if(d.isSelected){
// this.selected=i;
// console.log("CS :" + this.selected);
// }
});
}else{
// console.log(node.id + " DONT HAVE CHILDREN");
}
vm.$forceUpdate();
}
}
})
</script>
</body>

Related

Laravel returning wrong response

In my Controller I have the following code:
if (isset($request->validator) && $request->validator->fails())
{
$a =
[
"error_code" => 500,
"msg" => 'The given data was invalid.',
"errors" => $request->validator->errors()
];
$a = implode(" ",$a);
return back()->setStatusCode(422)->withErrors($request->validator->errors());
}
Basically, if the request form data was invalid, it is supposed to
Send a htpp status code of 422
Send the errors itemised
But the problem is that it is only obeying the first rule(about the htpp code) but not the second.
Ie it returns this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url=http://localhost:8000/dashboard/posts/create/?type=image" />
<title>Redirecting to http://localhost:8000/dashboard/posts/create/?type=image</title>
</head>
<body>
Redirecting to http://localhost:8000/dashboard/posts/create/?type=image.
<link rel='stylesheet' type='text/css' property='stylesheet' href='//localhost:8000/_debugbar/assets/stylesheets?v=1561562319'><script type='text/javascript' src='//localhost:8000/_debugbar/assets/javascript?v=1561562319'></script><script type="text/javascript">jQuery.noConflict(true);</script>
<script> Sfdump = window.Sfdump || (function (doc) { var refStyle = doc.createElement('style'), rxEsc = /([.*+?^${}()|\[\]\/\\])/g, idRx = /\bsf-dump-\d+-ref[012]\w+\b/, keyHint = 0 <= navigator.platform.toUpperCase().indexOf('MAC') ? 'Cmd' : 'Ctrl', addEventListener = function (e, n, cb) { e.addEventListener(n, cb, false); }; (doc.documentElement.firstElementChild || doc.documentElement.children[0]).appendChild(refStyle); if (!doc.addEventListener) { addEventListener = function (element, eventName, callback) { element.attachEvent('on' + eventName, function (e) { e.preventDefault = function () {e.returnValue = false;}; e.target = e.srcElement; callback(e); }); }; } function toggle(a, recursive) { var s = a.nextSibling || {}, oldClass = s.className, arrow, newClass; if (/\bsf-dump-compact\b/.test(oldClass)) { arrow = '▼'; newClass = 'sf-dump-expanded'; } else if (/\bsf-dump-expanded\b/.test(oldClass)) { arrow = '▶'; newClass = 'sf-dump-compact'; } else { return false; } if (doc.createEvent && s.dispatchEvent) { var event = doc.createEvent('Event'); event.initEvent('sf-dump-expanded' === newClass ? 'sfbeforedumpexpand' : 'sfbeforedumpcollapse', true, false); s.dispatchEvent(event); } a.lastChild.innerHTML = arrow; s.className = s.className.replace(/\bsf-dump-(compact|expanded)\b/, newClass); if (recursive) { try { a = s.querySelectorAll('.'+oldClass); for (s = 0; s < a.length; ++s) { if (-1 == a[s].className.indexOf(newClass)) { a[s].className = newClass; a[s].previousSibling.lastChild.innerHTML = arrow; } } } catch (e) { } } return true; }; function collapse(a, recursive) { var s = a.nextSibling || {}, oldClass = s.className; if (/\bsf-dump-expanded\b/.test(oldClass)) { toggle(a, recursive); return true; } return false; }; function expand(a, recursive) { var s = a.nextSibling || {}, oldClass = s.className; if (/\bsf-dump-compact\b/.test(oldClass)) { toggle(a, recursive); return true; } return false; }; function collapseAll(root) { var a = root.querySelector('a.sf-dump-toggle'); if (a) { collapse(a, true); expand(a); return true; } return false; } function reveal(node) { var previous, parents = []; while ((node = node.parentNode || {}) && (previous = node.previousSibling) && 'A' === previous.tagName) { parents.push(previous); } if (0 !== parents.length) { parents.forEach(function (parent) { expand(parent); }); return true; } return false; } function highlight(root, activeNode, nodes) { resetHighlightedNodes(root); Array.from(nodes||[]).forEach(function (node) { if (!/\bsf-dump-highlight\b/.test(node.className)) { node.className = node.className + ' sf-dump-highlight'; } }); if (!/\bsf-dump-highlight-active\b/.test(activeNode.className)) { activeNode.className = activeNode.className + ' sf-dump-highlight-active'; } } function resetHighlightedNodes(root) { Array.from(root.querySelectorAll('.sf-dump-str, .sf-dump-key, .sf-dump-public, .sf-dump-protected, .sf-dump-private')).forEach(function (strNode) { strNode.className = strNode.className.replace(/\bsf-dump-highlight\b/, ''); strNode.className = strNode.className.replace(/\bsf-dump-highlight-active\b/, ''); }); } return function (root, x) { root = doc.getElementById(root); var indentRx = new RegExp('^('+(root.getAttribute('data-indent-pad') || ' ').replace(rxEsc, '\\$1')+')+', 'm'), options = {"maxDepth":1,"maxStringLength":160,"fileLinkFormat":false}, elt = root.getElementsByTagName('A'), len = elt.length, i = 0, s, h, t = []; while (i < len) t.push(elt[i++]); for (i in x) { options[i] = x[i]; } function a(e, f) { addEventListener(root, e, function (e) { if ('A' == e.target.tagName) { f(e.target, e); } else if ('A' == e.target.parentNode.tagName) { f(e.target.parentNode, e); } else if (e.target.nextElementSibling && 'A' == e.target.nextElementSibling.tagName) { f(e.target.nextElementSibling, e, true); } }); }; function isCtrlKey(e) { return e.ctrlKey || e.metaKey; } function xpathString(str) { var parts = str.match(/[^'"]+|['"]/g).map(function (part) { if ("'" == part) { return '"\'"'; } if ('"' == part) { return "'\"'"; } return "'" + part + "'"; }); return "concat(" + parts.join(",") + ", '')"; } function xpathHasClass(className) { return "contains(concat(' ', normalize-space(#class), ' '), ' " + className +" ')"; } addEventListener(root, 'mouseover', function (e) { if ('' != refStyle.innerHTML) { refStyle.innerHTML = ''; } }); a('mouseover', function (a, e, c) { if (c) { e.target.style.cursor = "pointer"; } else if (a = idRx.exec(a.className)) { try { refStyle.innerHTML = '.phpdebugbar pre.sf-dump .'+a[0]+'{background-color: #B729D9; color: #FFF !important; border-radius: 2px}'; } catch (e) { } } }); a('click', function (a, e, c) { if (/\bsf-dump-toggle\b/.test(a.className)) { e.preventDefault(); if (!toggle(a, isCtrlKey(e))) { var r = doc.getElementById(a.getAttribute('href').substr(1)), s = r.previousSibling, f = r.parentNode, t = a.parentNode; t.replaceChild(r, a); f.replaceChild(a, s); t.insertBefore(s, r); f = f.firstChild.nodeValue.match(indentRx); t = t.firstChild.nodeValue.match(indentRx); if (f && t && f[0] !== t[0]) { r.innerHTML = r.innerHTML.replace(new RegExp('^'+f[0].replace(rxEsc, '\\$1'), 'mg'), t[0]); } if (/\bsf-dump-compact\b/.test(r.className)) { toggle(s, isCtrlKey(e)); } } if (c) { } else if (doc.getSelection) { try { doc.getSelection().removeAllRanges(); } catch (e) { doc.getSelection().empty(); } } else { doc.selection.empty(); } } else if (/\bsf-dump-str-toggle\b/.test(a.className)) { e.preventDefault(); e = a.parentNode.parentNode; e.className = e.className.replace(/\bsf-dump-str-(expand|collapse)\b/, a.parentNode.className); } }); elt = root.getElementsByTagName('SAMP'); len = elt.length; i = 0; while (i < len) t.push(elt[i++]); len = t.length; for (i = 0; i < len; ++i) { elt = t[i]; if ('SAMP' == elt.tagName) { a = elt.previousSibling || {}; if ('A' != a.tagName) { a = doc.createElement('A'); a.className = 'sf-dump-ref'; elt.parentNode.insertBefore(a, elt); } else { a.innerHTML += ' '; } a.title = (a.title ? a.title+'\n[' : '[')+keyHint+'+click] Expand all children'; a.innerHTML += '<span>▼</span>'; a.className += ' sf-dump-toggle'; x = 1; if ('sf-dump' != elt.parentNode.className) { x += elt.parentNode.getAttribute('data-depth')/1; } elt.setAttribute('data-depth', x); var className = elt.className; elt.className = 'sf-dump-expanded'; if (className ? 'sf-dump-expanded' !== className : (x > options.maxDepth)) { toggle(a); } } else if (/\bsf-dump-ref\b/.test(elt.className) && (a = elt.getAttribute('href'))) { a = a.substr(1); elt.className += ' '+a; if (/[\[{]$/.test(elt.previousSibling.nodeValue)) { a = a != elt.nextSibling.id && doc.getElementById(a); try { s = a.nextSibling; elt.appendChild(a); s.parentNode.insertBefore(a, s); if (/^[##]/.test(elt.innerHTML)) { elt.innerHTML += ' <span>▶</span>'; } else { elt.innerHTML = '<span>▶</span>'; elt.className = 'sf-dump-ref'; } elt.className += ' sf-dump-toggle'; } catch (e) { if ('&' == elt.innerHTML.charAt(0)) { elt.innerHTML = '…'; elt.className = 'sf-dump-ref'; } } } } } if (doc.evaluate && Array.from && root.children.length > 1) { root.setAttribute('tabindex', 0); SearchState = function () { this.nodes = []; this.idx = 0; }; SearchState.prototype = { next: function () { if (this.isEmpty()) { return this.current(); } this.idx = this.idx < (this.nodes.length - 1) ? this.idx + 1 : 0; return this.current(); }, previous: function () { if (this.isEmpty()) { return this.current(); } this.idx = this.idx > 0 ? this.idx - 1 : (this.nodes.length - 1); return this.current(); }, isEmpty: function () { return 0 === this.count(); }, current: function () { if (this.isEmpty()) { return null; } return this.nodes[this.idx]; }, reset: function () { this.nodes = []; this.idx = 0; }, count: function () { return this.nodes.length; }, }; function showCurrent(state) { var currentNode = state.current(), currentRect, searchRect; if (currentNode) { reveal(currentNode); highlight(root, currentNode, state.nodes); if ('scrollIntoView' in currentNode) { currentNode.scrollIntoView(true); currentRect = currentNode.getBoundingClientRect(); searchRect = search.getBoundingClientRect(); if (currentRect.top < (searchRect.top + searchRect.height)) { window.scrollBy(0, -(searchRect.top + searchRect.height + 5)); } } } counter.textContent = (state.isEmpty() ? 0 : state.idx + 1) + ' of ' + state.count(); } var search = doc.createElement('div'); search.className = 'sf-dump-search-wrapper sf-dump-search-hidden'; search.innerHTML = ' <input type="text" class="sf-dump-search-input"> <span class="sf-dump-search-count">0 of 0<\/span> <button type="button" class="sf-dump-search-input-previous" tabindex="-1"> <svg viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1683 1331l-166 165q-19 19-45 19t-45-19L896 965l-531 531q-19 19-45 19t-45-19l-166-165q-19-19-19-45.5t19-45.5l742-741q19-19 45-19t45 19l742 741q19 19 19 45.5t-19 45.5z"\/><\/svg> <\/button> <button type="button" class="sf-dump-search-input-next" tabindex="-1"> <svg viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1683 808l-742 741q-19 19-45 19t-45-19L109 808q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"\/><\/svg> <\/button> '; root.insertBefore(search, root.firstChild); var state = new SearchState(); var searchInput = search.querySelector('.sf-dump-search-input'); var counter = search.querySelector('.sf-dump-search-count'); var searchInputTimer = 0; var previousSearchQuery = ''; addEventListener(searchInput, 'keyup', function (e) { var searchQuery = e.target.value; /* Don't perform anything if the pressed key didn't change the query */ if (searchQuery === previousSearchQuery) { return; } previousSearchQuery = searchQuery; clearTimeout(searchInputTimer); searchInputTimer = setTimeout(function () { state.reset(); collapseAll(root); resetHighlightedNodes(root); if ('' === searchQuery) { counter.textContent = '0 of 0'; return; } var classMatches = [ "sf-dump-str", "sf-dump-key", "sf-dump-public", "sf-dump-protected", "sf-dump-private", ].map(xpathHasClass).join(' or '); var xpathResult = doc.evaluate('.//span[' + classMatches + '][contains(translate(child::text(), ' + xpathString(searchQuery.toUpperCase()) + ', ' + xpathString(searchQuery.toLowerCase()) + '), ' + xpathString(searchQuery.toLowerCase()) + ')]', root, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); while (node = xpathResult.iterateNext()) state.nodes.push(node); showCurrent(state); }, 400); }); Array.from(search.querySelectorAll('.sf-dump-search-input-next, .sf-dump-search-input-previous')).forEach(function (btn) { addEventListener(btn, 'click', function (e) { e.preventDefault(); -1 !== e.target.className.indexOf('next') ? state.next() : state.previous(); searchInput.focus(); collapseAll(root); showCurrent(state); }) }); addEventListener(root, 'keydown', function (e) { var isSearchActive = !/\bsf-dump-search-hidden\b/.test(search.className); if ((114 === e.keyCode && !isSearchActive) || (isCtrlKey(e) && 70 === e.keyCode)) { /* F3 or CMD/CTRL + F */ e.preventDefault(); search.className = search.className.replace(/\bsf-dump-search-hidden\b/, ''); searchInput.focus(); } else if (isSearchActive) { if (27 === e.keyCode) { /* ESC key */ search.className += ' sf-dump-search-hidden'; e.preventDefault(); resetHighlightedNodes(root); searchInput.value = ''; } else if ( (isCtrlKey(e) && 71 === e.keyCode) /* CMD/CTRL + G */ || 13 === e.keyCode /* Enter */ || 114 === e.keyCode /* F3 */ ) { e.preventDefault(); e.shiftKey ? state.previous() : state.next(); collapseAll(root); showCurrent(state); } } }); } if (0 >= options.maxStringLength) { return; } try { elt = root.querySelectorAll('.sf-dump-str'); len = elt.length; i = 0; t = []; while (i < len) t.push(elt[i++]); len = t.length; for (i = 0; i < len; ++i) { elt = t[i]; s = elt.innerText || elt.textContent; x = s.length - options.maxStringLength; if (0 < x) { h = elt.innerHTML; elt[elt.innerText ? 'innerText' : 'textContent'] = s.substring(0, options.maxStringLength); elt.className += ' sf-dump-str-collapse'; elt.innerHTML = '<span class=sf-dump-str-collapse>'+h+'<a class="sf-dump-ref sf-dump-str-toggle" title="Collapse"> ◀</a></span>'+ '<span class=sf-dump-str-expand>'+elt.innerHTML+'<a class="sf-dump-ref sf-dump-str-toggle" title="'+x+' remaining characters"> ▶</a></span>'; } } } catch (e) { } }; })(document); </script><style> .phpdebugbar pre.sf-dump { display: block; white-space: pre; padding: 5px; overflow: initial !important; } .phpdebugbar pre.sf-dump:after { content: ""; visibility: hidden; display: block; height: 0; clear: both; } .phpdebugbar pre.sf-dump span { display: inline; } .phpdebugbar pre.sf-dump .sf-dump-compact { display: none; } .phpdebugbar pre.sf-dump abbr { text-decoration: none; border: none; cursor: help; } .phpdebugbar pre.sf-dump a { text-decoration: none; cursor: pointer; border: 0; outline: none; color: inherit; } .phpdebugbar pre.sf-dump .sf-dump-ellipsis { display: inline-block; overflow: visible; text-overflow: ellipsis; max-width: 5em; white-space: nowrap; overflow: hidden; vertical-align: top; } .phpdebugbar pre.sf-dump .sf-dump-ellipsis+.sf-dump-ellipsis { max-width: none; } .phpdebugbar pre.sf-dump code { display:inline; padding:0; background:none; } .sf-dump-str-collapse .sf-dump-str-collapse { display: none; } .sf-dump-str-expand .sf-dump-str-expand { display: none; } .sf-dump-public.sf-dump-highlight, .sf-dump-protected.sf-dump-highlight, .sf-dump-private.sf-dump-highlight, .sf-dump-str.sf-dump-highlight, .sf-dump-key.sf-dump-highlight { background: rgba(111, 172, 204, 0.3); border: 1px solid #7DA0B1; border-radius: 3px; } .sf-dump-public.sf-dump-highlight-active, .sf-dump-protected.sf-dump-highlight-active, .sf-dump-private.sf-dump-highlight-active, .sf-dump-str.sf-dump-highlight-active, .sf-dump-key.sf-dump-highlight-active { background: rgba(253, 175, 0, 0.4); border: 1px solid #ffa500; border-radius: 3px; } .phpdebugbar pre.sf-dump .sf-dump-search-hidden { display: none !important; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper { font-size: 0; white-space: nowrap; margin-bottom: 5px; display: flex; position: -webkit-sticky; position: sticky; top: 5px; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > * { vertical-align: top; box-sizing: border-box; height: 21px; font-weight: normal; border-radius: 0; background: #FFF; color: #757575; border: 1px solid #BBB; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > input.sf-dump-search-input { padding: 3px; height: 21px; font-size: 12px; border-right: none; border-top-left-radius: 3px; border-bottom-left-radius: 3px; color: #000; min-width: 15px; width: 100%; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next, .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous { background: #F2F2F2; outline: none; border-left: none; font-size: 0; line-height: 0; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next { border-top-right-radius: 3px; border-bottom-right-radius: 3px; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next > svg, .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous > svg { pointer-events: none; width: 12px; height: 12px; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-count { display: inline-block; padding: 0 5px; margin: 0; border-left: none; line-height: 21px; font-size: 12px; }.phpdebugbar pre.sf-dump, .phpdebugbar pre.sf-dump .sf-dump-default{word-wrap: break-word; white-space: pre-wrap; word-break: normal}.phpdebugbar pre.sf-dump .sf-dump-num{font-weight:bold; color:#1299DA}.phpdebugbar pre.sf-dump .sf-dump-const{font-weight:bold}.phpdebugbar pre.sf-dump .sf-dump-str{font-weight:bold; color:#3A9B26}.phpdebugbar pre.sf-dump .sf-dump-note{color:#1299DA}.phpdebugbar pre.sf-dump .sf-dump-ref{color:#7B7B7B}.phpdebugbar pre.sf-dump .sf-dump-public{color:#000000}.phpdebugbar pre.sf-dump .sf-dump-protected{color:#000000}.phpdebugbar pre.sf-dump .sf-dump-private{color:#000000}.phpdebugbar pre.sf-dump .sf-dump-meta{color:#B729D9}.phpdebugbar pre.sf-dump .sf-dump-key{color:#3A9B26}.phpdebugbar pre.sf-dump .sf-dump-index{color:#1299DA}.phpdebugbar pre.sf-dump .sf-dump-ellipsis{color:#A0A000}.phpdebugbar pre.sf-dump .sf-dump-ns{user-select:none;}</style>
<script type="text/javascript">
var phpdebugbar = new PhpDebugBar.DebugBar();
phpdebugbar.addIndicator("php_version", new PhpDebugBar.DebugBar.Indicator({"icon":"code","tooltip":"Version"}), "right");
phpdebugbar.addTab("messages", new PhpDebugBar.DebugBar.Tab({"icon":"list-alt","title":"Messages", "widget": new PhpDebugBar.Widgets.MessagesWidget()}));
phpdebugbar.addIndicator("time", new PhpDebugBar.DebugBar.Indicator({"icon":"clock-o","tooltip":"Request Duration"}), "right");
phpdebugbar.addTab("timeline", new PhpDebugBar.DebugBar.Tab({"icon":"tasks","title":"Timeline", "widget": new PhpDebugBar.Widgets.TimelineWidget()}));
phpdebugbar.addIndicator("memory", new PhpDebugBar.DebugBar.Indicator({"icon":"cogs","tooltip":"Memory Usage"}), "right");
phpdebugbar.addTab("exceptions", new PhpDebugBar.DebugBar.Tab({"icon":"bug","title":"Exceptions", "widget": new PhpDebugBar.Widgets.ExceptionsWidget()}));
phpdebugbar.addTab("views", new PhpDebugBar.DebugBar.Tab({"icon":"leaf","title":"Views", "widget": new PhpDebugBar.Widgets.TemplatesWidget()}));
phpdebugbar.addTab("route", new PhpDebugBar.DebugBar.Tab({"icon":"share","title":"Route", "widget": new PhpDebugBar.Widgets.VariableListWidget()}));
phpdebugbar.addIndicator("currentroute", new PhpDebugBar.DebugBar.Indicator({"icon":"share","tooltip":"Route"}), "right");
phpdebugbar.addTab("queries", new PhpDebugBar.DebugBar.Tab({"icon":"database","title":"Queries", "widget": new PhpDebugBar.Widgets.LaravelSQLQueriesWidget()}));
phpdebugbar.addTab("emails", new PhpDebugBar.DebugBar.Tab({"icon":"inbox","title":"Mails", "widget": new PhpDebugBar.Widgets.MailsWidget()}));
phpdebugbar.addTab("auth", new PhpDebugBar.DebugBar.Tab({"icon":"lock","title":"Auth", "widget": new PhpDebugBar.Widgets.VariableListWidget()}));
phpdebugbar.addIndicator("auth.name", new PhpDebugBar.DebugBar.Indicator({"icon":"user","tooltip":"Auth status"}), "right");
phpdebugbar.addTab("gate", new PhpDebugBar.DebugBar.Tab({"icon":"list-alt","title":"Gate", "widget": new PhpDebugBar.Widgets.MessagesWidget()}));
phpdebugbar.addTab("session", new PhpDebugBar.DebugBar.Tab({"icon":"archive","title":"Session", "widget": new PhpDebugBar.Widgets.VariableListWidget()}));
phpdebugbar.addTab("request", new PhpDebugBar.DebugBar.Tab({"icon":"tags","title":"Request", "widget": new PhpDebugBar.Widgets.HtmlVariableListWidget()}));
phpdebugbar.setDataMap({
"php_version": ["php.version", ],
"messages": ["messages.messages", []],
"messages:badge": ["messages.count", null],
"time": ["time.duration_str", '0ms'],
"timeline": ["time", {}],
"memory": ["memory.peak_usage_str", '0B'],
"exceptions": ["exceptions.exceptions", []],
"exceptions:badge": ["exceptions.count", null],
"views": ["views", []],
"views:badge": ["views.nb_templates", 0],
"route": ["route", {}],
"currentroute": ["route.uri", ],
"queries": ["queries", []],
"queries:badge": ["queries.nb_statements", 0],
"emails": ["swiftmailer_mails.mails", []],
"emails:badge": ["swiftmailer_mails.count", null],
"auth": ["auth.guards", {}],
"auth.name": ["auth.names", ],
"gate": ["gate.messages", []],
"gate:badge": ["gate.count", null],
"session": ["session", {}],
"request": ["request", {}]
});
phpdebugbar.restoreState();
phpdebugbar.ajaxHandler = new PhpDebugBar.AjaxHandler(phpdebugbar, undefined, true);
phpdebugbar.ajaxHandler.bindToXHR();
phpdebugbar.setOpenHandler(new PhpDebugBar.OpenHandler({"url":"http:\/\/localhost:8000\/_debugbar\/open"}));
phpdebugbar.addDataSet({"__meta":{"id":"Xd39066258b4a2621a0ed4dcd084f5d32","datetime":"2019-06-27 06:31:41","utime":1561617101.172856,"method":"POST","uri":"\/upload","ip":"127.0.0.1"},"php":{"version":"7.3.1","interface":"cli-server"},"messages":{"count":0,"messages":[]},"time":{"start":1561617100.455814,"end":1561617101.172856,"duration":0.7170422077178955,"duration_str":"717.04ms","measures":[{"label":"Booting","start":1561617100.455814,"relative_start":0,"end":1561617100.836836,"relative_end":1561617100.836836,"duration":0.38102221488952637,"duration_str":"381.02ms","params":[],"collector":null},{"label":"Application","start":1561617100.852837,"relative_start":0.39702320098876953,"end":1561617101.172856,"relative_end":0,"duration":0.320019006729126,"duration_str":"320.02ms","params":[],"collector":null}]},"memory":{"peak_usage":12164672,"peak_usage_str":"11.6MB"},"exceptions":{"count":0,"exceptions":[]},"views":{"nb_templates":0,"templates":[]},"route":{"uri":"POST upload","middleware":"web","controller":"App\\Http\\Controllers\\PostController#upload","namespace":"App\\Http\\Controllers","prefix":null,"where":[],"as":"upload","file":"\\app\\Http\\Controllers\\PostController.php:360-468"},"queries":{"nb_statements":1,"nb_failed_statements":0,"accumulated_duration":0.017,"accumulated_duration_str":"17ms","statements":[{"sql":"select * from `users` where `id` = 15 limit 1","type":"query","params":[],"bindings":["15"],"hints":["Use <code>SELECT *<\/code> only if you need all columns from table","<code>LIMIT<\/code> without <code>ORDER BY<\/code> causes non-deterministic results, depending on the query execution plan"],"backtrace":[{"index":15,"namespace":null,"name":"\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\EloquentUserProvider.php","line":52},{"index":16,"namespace":null,"name":"\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\SessionGuard.php","line":131},{"index":17,"namespace":null,"name":"\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\GuardHelpers.php","line":60},{"index":18,"namespace":null,"name":"\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\AuthManager.php","line":292},{"index":19,"namespace":null,"name":"\\vendor\\laravel\\framework\\src\\Illuminate\\Support\\Facades\\Facade.php","line":223},{"index":20,"namespace":null,"name":"\\app\\Http\\Requests\\StorePostRequest.php","line":17},{"index":23,"namespace":null,"name":"\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\BoundMethod.php","line":87},{"index":24,"namespace":null,"name":"\\vendor\\laravel\\framework\\src\\Illuminate\\
I'm guessing it has do with phpdebugbar
The error messages are stored in the session. To display them you need to access the session in your blade file like {{session('errors')->first('error1')}}.
Take a look at this post for more examples.
I had to remove the phpdebugbar.
\Debugbar::disable();

How to optimize display & interactive with large svg image without Lag in FabricJS

I have a fabricJS editor with some large svg files, therefore, when I interactive with ( move / drag ) items on the editor I fill it very lag & heavy.
How to optimize using large svg files with fabricJS ?
big_image_1.svg: 4.4MB
big_image_2.svg: 6.1MB
big_image_3.svg: 4.1MB
big_image_4.svg: 13.6MB
Here is my code:
var canvas;
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
for (var i = 0; i < 4; i++) {
var bigImage = new fabric.Image();
bigImage.left = 10 * (i + 1);
bigImage.top = 10 * (i + 1);
bigImage["objectCaching"] = true;
canvas.add(bigImage);
bigImage.setSrc('https://futushigame.firebaseapp.com/big_image/big_image_' + (i + 1) + '.svg', function(imageObject) {
imageObject.set('dirty', true);
canvas.renderAll();
setObjectCoords();
});
}
function setObjectCoords() {
canvas.forEachObject(function(object) {
object.setCoords();
});
}
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>
Drag items are filling heavy & lag
You can rewrite needsItsOwnCache from fabric.Image class.
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
for (var i = 0; i < 4; i++) {
var bigImage = new fabric.Image();
bigImage.left = 10 * (i + 1);
bigImage.top = 10 * (i + 1);
// bigImage["objectCaching"] = true;
bigImage["ownCaching"] = true;
// bigImage["clipPath"] = [];
canvas.add(bigImage);
bigImage.setSrc('https://futushigame.firebaseapp.com/big_image/big_image_' + (i + 1) + '.svg', function(imageObject) {
//imageObject.set('dirty', true);
canvas.renderAll();
setObjectCoords();
});
}
function setObjectCoords() {
canvas.forEachObject(function(object) {
object.setCoords();
});
}
fabric.Image.prototype.needsItsOwnCache = function() {
return true
}
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>

D3JS: Unable to append a text element only once

I have this code which generates 9 donuts charts. the thing is that the SVG canvas gets appended so many times to the DOM, as many as donuts charts are drawn, and when I try to place a single text element on the top of the screen (as a big title which explain the graphics), it gets appended 9 times as well (in every SVG canvas which hold each donut). I need to have only one SVG canvas and inside it the 9 donuts, but I'm having a hard time trying to achieve it.
Here's a running snippet of what I have so far.
$("#chartdiv").empty()
var dataObj = {
data1: [19, 81],
data2: [15, 85],
data3: [13, 91],
data4: [8, 92],
data5: [7, 93],
data7: [6, 94],
data8: [5, 95],
data9: [4, 96],
data10: [3, 97],
data11: [2, 98],
data11: [1, 99],
data12: [0, 100],
};
var newarr = ["Manufacturing", "Technology", "Other", "Engineering", "Automotive", "Consulting/professiona services", "Entertaiment and media", "Financial services", "Apparel and textile", "Construction", "Academic and educational", "Legal services"]
var width = 140,
height = 140,
radius = (Math.min(width, height) / 2.8);
function drawDonut(data, divchart, index, chartName) {
var color = ["#00338D", "#dedede"];
var pie = d3.pie()
.sortValues(null)
.value(function(d) {
return d
})(data);
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(radius - (radius / 1.9));
var labelArc = d3.arc()
.outerRadius(radius - 31)
.innerRadius(radius - 31);
var svg = d3.select("#chartdiv")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + 75 + "," + 50 + ")");
var g = svg.selectAll("arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
function easeInverse(ease) {
return function(e) {
var min = 0,
max = 1;
while (max - min > 1e-3) {
var mid = (max + min) * 0.5;
emid = ease(mid);
if (emid > e) {
max = mid;
} else {
min = mid;
}
}
return max;
}
}
var inverseCubic = easeInverse(d3.easeCubic);
var oneOver2Pi = 1.0 / (2 * Math.PI);
var total_msec = 900;
g.append("path")
.style("fill", function(d, i) {
return color[i];
})
.transition()
.ease(d3.easeLinear)
.delay(function(d) {
return total_msec * inverseCubic(d.startAngle * oneOver2Pi);
})
.duration(function(d) {
return total_msec * (inverseCubic(d.endAngle * oneOver2Pi) - inverseCubic(d.startAngle * oneOver2Pi));
})
.attrTween("d", arcTween);
function arcTween(d) {
var i = d3.interpolate(inverseCubic(d.startAngle * oneOver2Pi), inverseCubic(d.endAngle * oneOver2Pi));
return function(t) {
d.endAngle = 2 * Math.PI * d3.easeCubic(i(t));
return arc(d);
}
}
g.append("text")
.attr("transform", "translate(0,5) scale(1.4)")
.attr("font-weight", "bold")
.attr("class", "st0 donutsTextElemnt")
.attr("font-size", "11px")
.attr("text-anchor", "middle")
.html(data[0] + "%");
svg.append("foreignObject")
.attr("transform", "translate(-30,50) scale(.75)")
.attr("width", 120)
.attr("height", 80)
.attr("class", "caption 3rForeignObj")
.append("xhtml:body")
.html(newarr[index])
.style("background", "white");
var lastDonut = $("#donutdiv").children().eq(6)
lastDonut.css({
'transform': 'translate(0 , 20px)'
});
}
Object.keys(dataObj).forEach(function(d, i) {
drawDonut(dataObj[d], '#pie' + (i + 1), i, 'chart' + (i + 1));
});
body {
background: rgb(92, 29, 186);
height: 100vh;
}
* {
box-sizing: border-box;
}
.list-group-item {
font-size: 24px;
background: inherit;
border: none;
color: #fff!important;
}
/* .action{
font-size: 14px!important;
background: inherit;
border: none;
color:#fff!important;
} */
.list-group-item:hover {
color: black!important;
}
.firstPage {
background: #470a68;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%)
}
.secondPage {
background: #00A3A1;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
;
-o-transform: translate(-50%, -50%);
;
transform: translate(-50%, -50%);
;
}
.thirdPage {
background: #00A3A1;
}
.fourthPage {
background: #f45f42;
}
.submenuTitle p {
font-size: 30px;
color: #fff;
}
.sectionsTitle {
font-size: 52px!important;
}
.inactive {
display: none;
}
.active {
display: block;
}
#chartdiv {
background: #fff;
}
.chart {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.heightZero {
height: 0;
overflow: hidden
}
#keyframes slideUp {
to {
height: 100%
}
}
.slideUp {
animation: slideUp .6s ease-in forwards;
}
.thirdDonutsDiv {
display: inline
}
a {
font-size: 16px!important;
}
.back {
transform: scale(.7)
}
.container-fluid {
width: 512px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%)
}
.sectionsTitle {
font-family: KPMG Extralight;
color: white;
font-weight: bold;
}
p.mainTitle {
color: #fff;
font-size: 115px;
font-family: KPMG Extralight;
margin-top: 5px;
}
p.standardP {
color: #fff;
font-family: univers;
font-size: 1.666rem;
line-height: 1.2;
margin: 1rem 1;
margin-top: 30px;
}
h3.mainTitle {
color: #fff;
font-family: KPMG;
margin-top: 14px;
margin-bottom: 14px;
font-size: 3.8rem;
font-weight: bolder;
}
p.standardP {
color: #fff;
font-family: univers;
font-size: 1.666rem;
line-height: 1.2;
margin: 1rem 1;
margin-top: 30px;
}
ul {
list-style-type: none;
padding: 0;
margin-right: 10px;
margin-left: 10px;
}
label {
width: 100%;
height: 100%;
padding: 0.85rem 1rem;
background-color: hsla(0, 0%, 100%, 0);
color: #fff;
cursor: pointer;
border-radius: 4px;
margin-bottom: 11px;
transition: all .4s;
font-size: 16px;
font-weight: normal;
}
label:hover {
background-color: white;
color: #000;
transition: background-color .2s
}
.labelUnselected {
background-color: hsla(0, 0%, 100%, .6);
color: #fff;
}
div.mainDiv p {
word-wrap: break-word;
line-height: 100%;
}
input {
display: none;
}
.backSubMenu1 {
text-align: center;
}
/* donut chart 4*/
.st0 {
fill: #00338D;
}
#fourtySeven {
transform: translate(50px, 0px)
}
#twentyEight {
transform: translate(-63.104974985120286px, 86.28081103480314px)
}
.icon2 {
opacity: 0;
animation: fadeIn 1s linear 1.5s forwards;
transform: translate(-50px, -45px)
}
#keyframes fadeIn {
to {
opacity: 1;
}
}
.rect {
opacity: 0;
animation: fadeIn 1.3s linear 1.5s forwards;
}
#keyframes fadeIn {
to {
opacity: 1;
}
}
.ifram {
width: 512px;
}
.iconXY {
opacity: 0;
animation: fadeIn 1.5s linear 1.8s forwards;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<div class="row">
<div class="col-sm-12" id="chartdiv"></div>
<div class="text-left backSubMenu1">
<i class="fas fa-chevron-left back" style="font-size: 40px;color:aliceblue" targetX="secondPage">
</i>
</div>
<div id="pie1" class="thirdDonutsDiv"></div>
<div id="pie2" class="thirdDonutsDiv"></div>
<div id="pie3" class="thirdDonutsDiv"></div>
<div id="pie4" class="thirdDonutsDiv"></div>
<div id="pie5" class="thirdDonutsDiv"></div>
<div id="pie6" class="thirdDonutsDiv"></div>
<div id="pie7" class="thirdDonutsDiv"></div>
<div id="pie8" class="thirdDonutsDiv"></div>
<div id="pie9" class="thirdDonutsDiv"></div>
</div>
Here's a more d3ish refactor that achieves your goal of one SVG containing all pie charts:
<!DOCTYPE html>
<html>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<div class="row">
<div class="col-sm-12" id="chartdiv">
</div>
</div>
<script>
var dataObj = {
data1: [19, 81],
data2: [15, 85],
data3: [13, 91],
data4: [8, 92],
data5: [7, 93],
data7: [6, 94],
data8: [5, 95],
data9: [4, 96],
data10: [3, 97],
data11: [2, 98],
data11: [1, 99],
data12: [0, 100],
};
var newarr = ["Manufacturing", "Technology", "Other", "Engineering", "Automotive", "Consulting/professiona services", "Entertaiment and media", "Financial services", "Apparel and textile", "Construction", "Academic and educational", "Legal services"]
var width = 140,
height = 140,
radius = (Math.min(width, height) / 2.8),
numCol = 4;
var svg = d3.select("#chartdiv")
.append("svg")
.attr("width", width * numCol)
.attr("height", height * (newarr.length / numCol));
svg.selectAll(".donut")
.data(d3.values(dataObj))
.enter()
.append("g")
.attr("class", "donut")
.each(drawDonut);
function drawDonut(data, index) {
var color = ["#00338D", "#dedede"];
var pie = d3.pie()
.sortValues(null)
.value(function(d) {
return d
})(data);
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(radius - (radius / 1.9));
var labelArc = d3.arc()
.outerRadius(radius - 31)
.innerRadius(radius - 31);
var xPos = 75 + ((index % numCol) * width),
yPos = 50 + (Math.floor(index / numCol) * height);
var group = svg
.append("g")
.attr("transform", "translate(" + xPos + "," + yPos + ")");
var g = group.selectAll("arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
function easeInverse(ease) {
return function(e) {
var min = 0,
max = 1;
while (max - min > 1e-3) {
var mid = (max + min) * 0.5;
emid = ease(mid);
if (emid > e) {
max = mid;
} else {
min = mid;
}
}
return max;
}
}
var inverseCubic = easeInverse(d3.easeCubic);
var oneOver2Pi = 1.0 / (2 * Math.PI);
var total_msec = 900;
g.append("path")
.style("fill", function(d, i) {
return color[i];
})
.transition()
.ease(d3.easeLinear)
.delay(function(d) {
return total_msec * inverseCubic(d.startAngle * oneOver2Pi);
})
.duration(function(d) {
return total_msec * (inverseCubic(d.endAngle * oneOver2Pi) - inverseCubic(d.startAngle * oneOver2Pi));
})
.attrTween("d", arcTween);
function arcTween(d) {
var i = d3.interpolate(inverseCubic(d.startAngle * oneOver2Pi), inverseCubic(d.endAngle * oneOver2Pi));
return function(t) {
d.endAngle = 2 * Math.PI * d3.easeCubic(i(t));
return arc(d);
}
}
g.append("text")
.attr("transform", "translate(0,5) scale(1.4)")
.attr("font-weight", "bold")
.attr("class", "st0 donutsTextElemnt")
.attr("font-size", "11px")
.attr("text-anchor", "middle")
.html(data[0] + "%");
svg.append("text")
.attr("transform", "translate(" + (xPos) + "," + (yPos + height / 2.4) + ") scale(.75)")
.attr("text-anchor", "middle")
.text(newarr[index]);
}
</script>
</body>
</html>

Add hyperlink to d3.js table cells with dataset

Suppose there's a given tab-separated values (TSV) file named datatable.tsv:
Title URL DataChange
A http://localhost/A.html 1
B http://localhost/B.html -2
C http://localhost/C.html 0
D http://localhost/D.html 12
E http://localhost/E.html -9
I need to generate a data table with D3.js and implement following requirements:
The first column displays a hyperlink with Title as text and URL as href.
The second column displays the DataChange value.
Digit values should be right aligned.
If the DataChange value is positive, set class "add"; otherwise set class "minus".
For my code as below, my questions are:
How can I add hyperlink to the first column?
Is there other method to improve the code for adding classes "right", "add" and "minus"?
Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Data Table</title>
<style>
table { border-collapse: collapse; color: #333; background-color: #F7F6F3; }
table thead { font-weight: bold; background-color: #CCC; cursor: default; }
table tbody tr:hover { background-color: #FFC; }
td { border: solid 1px #CCC; padding: 0 1ex; }
.even { color: #284775; background-color: White; }
.left { text-align: left; }
.right { text-align: right; }
.add { color: green; }
.minus { color: red; }
</style>
</head>
<body>
<div id="table"></div>
<script src="d3.min.js"></script>
<script>
var table = d3.select("#table").append("table"),
thead = table.append("thead"),
tbody = table.append("tbody");
thead.append("th").text("Title");
thead.append("th").text("Data Change");
d3.tsv("datatable.tsv", function(error, data) {
if (error) throw error;
var tr = tbody.selectAll("tr")
.data(data)
.enter().append("tr")
.classed("even", function(d, i) { return i % 2 == 1; });
var td = tr.selectAll("td")
.data(function(d) { return [d.Title, d3.format("+")(+d.DataChange)]; })
.enter().append("td")
.text(function(d) { return d; })
.classed("right", function(d, i) { return i == 1; })
.classed("add", function(d, i) { return i == 1 && d.charAt(0) == "+"; })
.classed("minus", function(d, i) { return i == 1 && d.charAt(0) == "-"; });
});
</script>
</body>
</html>
I found another similar question gave a solution using selection.html. But in my case the href reads from URL field and URL field should not be displayed in the table.
I found a solution like this:
var td = tr.selectAll("td")
.data(function(d) {
return [
''+htmlencode(d.Title)+'',
d3.format("+")(+d.DataChange)
];
})
.enter().append("td")
.html(function(d) { return d; })
.attr("class", function(d, i) {
return i == 1 ? "right " + (d.charAt(0) == "+" ? "add" : "minus") : null;
});
I didn't understand the selection.data clearly enough when I asked this question. :)
You can try using, the .each() function for each row to add the appropriate cells, like so:
var tr = tbody.selectAll("tr")
.data(data)
.enter().append("tr")
.classed("even", function(d, i) { return i % 2 == 1; });
tr.each(function(d) {
var self = d3.select(this);
self
.append("td")
.append("a")
.attr("href", d.URL)
.text(d.Title);
self.append("td")
.html(d["Data Change"]);
});
Here's a working block you can play with.

Uncaught TypeError: Cannot read property 'length' of undefined

I am trying to get some data in my map, however I have the following error:
Uncaught TypeError: Cannot read property 'length' of undefined.
This is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3 Test</title>
<script type="text/javascript" src="http://localhost/webserver/d3/d3.js"></script>
<script type="text/javascript" src="http://localhost/webserver/topojson/topojson.js"></script>
<style type="text/css">
div.bar {
display: inline-block;
width: 20px;
height: 75px;
background-color: teal;
margin-right: 2px;
}
.pumpkin {
fill: rgba(128, 0, 128, 0.75);
stroke: yellow;
stroke-width: 5;
}
.apple {
fill: rgba(0, 255, 0, 0.55);
stroke: green;
stroke-width: 15;
}
.orange {
fill: rgba(255, 255, 0, 0.55);
stroke: orange;
stroke-width: 10;
}
.subunit { fill: #cdc; }
.subunit-label {
fill: #777;
fill-opacity: .25;
font-size: 30px;
font-weight: 300;
text-anchor: middle;}
.provincie {fill: none; }
.Utrecht {fill: #ddd; }
.Zuid-Holland {fill: #dde; }
.Noord-Holland {fill: #dee; }
.Drenthe {fill: #aae; }
.Gelderland {fill: #eee; }
.Friesland {fill: #ddc; }
.Groningen {fill: #dcc; }
.Limburg {fill: #ccc; }
.Noord-Brabant {fill: #ddb; }
.Overijssel {fill: #dbb; }
.Zeeland {fill: #bbb; }
</style>
</head>
<body>
<script type="text/javascript">
var width = 960, height = 860;
var projection = d3.geo.albers()
.center([6, 49.40])
.rotate([0, -1.9])
.parallels([50, 60])
.scale(11000)
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
//Define quantize scale to sort data values into buckets of color
var color = d3.scale.quantize()
.range(["rgb(237,248,233)","rgb(186,228,179)","rgb(116,196,118)","rgb(49,163,84)","rgb(0,109,44)"]);
//Load in data
d3.csv("http://localhost/webserver/data/beroepsbevolking.csv", function(data) {
//Set input domain for color scale
color.domain([
d3.min(data, function(d) { return d.value; }),
d3.max(data, function(d) { return d.value; })
]);
d3.json("http://localhost/webserver/data/nl2.json", function(error, nl) {
svg.selectAll(".subunit")
.data(topojson.object(nl, nl.objects.subunits).geometries)
.enter().append("path")
.attr("class", function(d) { return "subunit " + d.id; })
.attr("d", path);
svg.selectAll(".subunit-label")
.data(topojson.object(nl, nl.objects.subunits).geometries)
//svg.selectAll(".provincie")
.data(topojson.object(nl, nl.objects.provincies).geometries)
.enter().append("path")
// .attr("class", function(d) { return "provincie " + d.properties.name; })
.attr("d", path);
//Merge the ag. data and GeoJSON
//Loop through once for each ag. data value
d3.json("http://localhost/webserver/data/nl2.json" ,function(json) {
for (var i = 0; i < data.length; i++) {
//Grab provincie name
var dataProvincie = data[i].provincie;
//Grab data value, and convert from string to float
var dataValue = parseFloat(data[i].value);
//Find the corresponding provincie inside the GeoJSON
for (var j = 0; j < json.features.length; j++) {
var jsonProvincie = json.features[j].properties.name;
if (dataProvincie == jsonProvincie) {
//Copy the data value into the JSON
json.features[j].properties.value = dataValue;
//Stop looking through the JSON
break;
}
}
}
//Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", function(d) {
//Get data value
var value = d.properties.value;
if (value) {
//If value exists…
return color(value);
} else {
//If value is undefined…
return "#ccc";
}
});
});
});
});
</script>
</body>
</html>
It goes wrong at line 115:
for (var j = 0; j < json.features.length; j++) {
Why?
Your JSON doesn't have a features field. In addition, you've missed an argument in the d3.json function -- in your second call, json will actually be bound to the error. Change
d3.json("http://localhost/webserver/data/nl2.json" ,function(json) {
to
d3.json("http://localhost/webserver/data/nl2.json" ,function(error, json) {
The second call to d3.json seems unnecessary -- at that point, you have the data in nl2.json already in the nl variable.
The name of the parameter is "json", not "data".
Make them the same name and it should work.
Also; get a hint from the error message; "data" is undefined.

Resources