Skip to content

Commit

Permalink
v1.2.2 change in packaje.json
Browse files Browse the repository at this point in the history
  • Loading branch information
Daryl11018 committed Sep 19, 2020
1 parent bea9363 commit 7e746e8
Show file tree
Hide file tree
Showing 3 changed files with 281 additions and 4 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@daryl110/go-chart",
"version": "1.2.1",
"version": "1.2.2",
"description": "library to easily build charts",
"main": "index.js",
"author": "daryl110",
Expand Down
278 changes: 278 additions & 0 deletions src/modules/d3/charts/BubbleDrag.chart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
const {
appendChart,
d3
} = require('../others/d3.utils');

module.exports = (
htmlElementContainer,
idElement,
data,
backgroundColor = 'white'
) => {
const svg = d3.create('svg');

svg.style('background-color', backgroundColor);

/*eslint-enable indent*/
let width = 5500; // get width in pixels
let height = 700;
let centerX = width * 0.5;
let centerY = height * 0.5;
let strength = 0.05;
let focusedNode;
console.log('width', width);

let format = d3.format(',d');

let scaleColor = d3.scaleOrdinal(d3.schemeCategory10);

// use pack to calculate radius of the circle
let pack = d3.pack()
.size([width, height])
.padding(1.5);

let forceCollide = d3.forceCollide(d => d.r + 1);

// use the force
let simulation = d3.forceSimulation()
// .force('link', d3.forceLink().id(d => d.id))
.force('charge', d3.forceManyBody())
.force('collide', forceCollide)
// .force('center', d3.forceCenter(centerX, centerY))
.force('x', d3.forceX(centerX).strength(strength))
.force('y', d3.forceY(centerY).strength(strength));

// reduce number of circles on mobile screen due to slow computation
if ('matchMedia' in window && window.matchMedia('(max-device-width: 767px)').matches) {
data = data.filter(el => {
return el.value >= 50;
});
}

let root = d3.hierarchy({children: data})
.sum(d => d.value);

// we use pack() to automatically calculate radius conveniently only
// and get only the leaves
let nodes = pack(root).leaves().map(node => {
// console.log('node:', node.x, (node.x - centerX) * 2);
const data = node.data;
return {
x: centerX + (node.x - centerX) * 3, // magnify start position to have transition to center movement
y: centerY + (node.y - centerY) * 3,
r: 0, // for tweening
radius: node.r, //original radius
id: data.cat + '.' + (data.name.replace(/\s/g, '-')),
cat: data.cat,
name: data.name,
value: data.value,
icon: data.icon ? data.icon : undefined,
desc: data.desc,
};
});
simulation.nodes(nodes).on('tick', ticked);

svg.style('background-color', '#eee');
let node = svg.selectAll('.node')
.data(nodes)
.enter().append('g')
.attr('class', 'node')
.call(d3.drag()
.on('start', (d) => {
if (!d3.event.active) {
simulation.alphaTarget(0.2).restart();
}
d.fx = d.x;
d.fy = d.y;
})
.on('drag', (d) => {
d.fx = d3.event.x;
d.fy = d3.event.y;
})
.on('end', (d) => {
if (!d3.event.active) {
simulation.alphaTarget(0);
}
d.fx = null;
d.fy = null;
}));

node.append('circle')
.attr('id', d => d.id)
.attr('r', 0)
.style('fill', d => scaleColor(d.cat))
.transition().duration(2000).ease(d3.easeElasticOut)
.tween('circleIn', (d) => {
let i = d3.interpolateNumber(0, d.radius);
return (t) => {
d.r = i(t);
simulation.force('collide', forceCollide);
};
});

node.append('clipPath')
.attr('id', d => `clip-${d.id}`)
.append('use')
.attr('xlink:href', d => `#${d.id}`);

// display text as circle icon
node.filter(d => !String(d.icon).includes('img/'))
.append('text')
.classed('node-icon', true)
.attr('clip-path', d => `url(#clip-${d.id})`)
.selectAll('tspan')
.data(({ icon }) => icon ? d.icon.split(';') : [] )
.enter()
.append('tspan')
.attr('x', 0)
.attr('y', (d, i, nodes) => (13 + (i - nodes.length / 2 - 0.5) * 10))
.text(name => name);

// display image as circle icon
node.filter(d => String(d.icon).includes('img/'))
.append('image')
.classed('node-icon', true)
.attr('clip-path', d => `url(#clip-${d.id})`)
.attr('xlink:href', d => d.icon)
.attr('x', d => -d.radius * 0.7)
.attr('y', d => -d.radius * 0.7)
.attr('height', d => d.radius * 2 * 0.7)
.attr('width', d => d.radius * 2 * 0.7);

node.append('title')
.text(d => (d.cat + '::' + d.name + '\n' + format(d.value)));

/*
<foreignObject class="circle-overlay" x="10" y="10" width="100" height="150">
<div class="circle-overlay__inner">
<h2 class="circle-overlay__title">ReactJS</h2>
<p class="circle-overlay__body">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam, sunt, aspernatur. Autem repudiandae, laboriosam. Nulla quidem nihil aperiam dolorem repellendus pariatur, quaerat sed eligendi inventore ipsa natus fugiat soluta doloremque!</p>
</div>
</foreignObject>
*/
let infoBox = node.append('foreignObject')
.classed('circle-overlay hidden', true)
.attr('x', -350 * 0.5 * 0.8)
.attr('y', -350 * 0.5 * 0.8)
.attr('height', 350 * 0.8)
.attr('width', 350 * 0.8)
.append('xhtml:div')
.classed('circle-overlay__inner', true);

infoBox.append('h2')
.classed('circle-overlay__title', true)
.text(d => d.name);

infoBox.append('p')
.classed('circle-overlay__body', true)
.html(d => d.desc);


node.on('click', (currentNode) => {
d3.event.stopPropagation();
console.log('currentNode', currentNode);
let currentTarget = d3.event.currentTarget; // the <g> el

if (currentNode === focusedNode) {
// no focusedNode or same focused node is clicked
return;
}
let lastNode = focusedNode;
focusedNode = currentNode;

simulation.alphaTarget(0.2).restart();
// hide all circle-overlay
d3.selectAll('.circle-overlay').classed('hidden', true);
d3.selectAll('.node-icon').classed('node-icon--faded', false);

// don't fix last node to center anymore
if (lastNode) {
lastNode.fx = null;
lastNode.fy = null;
node.filter((d, i) => i === lastNode.index)
.transition().duration(2000).ease(d3.easePolyOut)
.tween('circleOut', () => {
let irl = d3.interpolateNumber(lastNode.r, lastNode.radius);
return (t) => {
lastNode.r = irl(t);
};
})
.on('interrupt', () => {
lastNode.r = lastNode.radius;
});
}

// if (!d3.event.active) simulation.alphaTarget(0.5).restart();

d3.transition().duration(2000).ease(d3.easePolyOut)
.tween('moveIn', () => {
console.log('tweenMoveIn', currentNode);
let ix = d3.interpolateNumber(currentNode.x, centerX);
let iy = d3.interpolateNumber(currentNode.y, centerY);
let ir = d3.interpolateNumber(currentNode.r, centerY * 0.5);
return function (t) {
// console.log('i', ix(t), iy(t));
currentNode.fx = ix(t);
currentNode.fy = iy(t);
currentNode.r = ir(t);
simulation.force('collide', forceCollide);
};
})
.on('end', () => {
simulation.alphaTarget(0);
let $currentGroup = d3.select(currentTarget);
$currentGroup.select('.circle-overlay')
.classed('hidden', false);
$currentGroup.select('.node-icon')
.classed('node-icon--faded', true);

})
.on('interrupt', () => {
console.log('move interrupt', currentNode);
currentNode.fx = null;
currentNode.fy = null;
simulation.alphaTarget(0);
});

});

// blur
d3.select(document).on('click', () => {
let target = d3.event.target;
// check if click on document but not on the circle overlay
if (!target.closest('#circle-overlay') && focusedNode) {
focusedNode.fx = null;
focusedNode.fy = null;
simulation.alphaTarget(0.2).restart();
d3.transition().duration(2000).ease(d3.easePolyOut)
.tween('moveOut', function () {
console.log('tweenMoveOut', focusedNode);
let ir = d3.interpolateNumber(focusedNode.r, focusedNode.radius);
return function (t) {
focusedNode.r = ir(t);
simulation.force('collide', forceCollide);
};
})
.on('end', () => {
focusedNode = null;
simulation.alphaTarget(0);
})
.on('interrupt', () => {
simulation.alphaTarget(0);
});

// hide all circle-overlay
d3.selectAll('.circle-overlay').classed('hidden', true);
d3.selectAll('.node-icon').classed('node-icon--faded', false);
}
});

function ticked() {
node
.attr('transform', d => `translate(${d.x},${d.y})`)
.select('circle')
.attr('r', d => d.r);
}

appendChart(svg, idElement, htmlElementContainer);
};
5 changes: 2 additions & 3 deletions src/modules/d3/charts/collapsableTree.chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const {
* <code>{ name: string, children: array[data] }</code>
* @param {number} width - chart width inside the container
* @param {number} height - chart height inside the container
* @param {Object} margin - view box container
* @param {string} backgroundColor - background color for the chart
* @example D3.collapsableTreeChart(
* document.getElementById('charts'),
Expand Down Expand Up @@ -91,11 +92,11 @@ module.exports = (
data,
width = 1050,
height = 300,
margin = { top: 10, right: 120, bottom: 10, left: 120 },
backgroundColor = 'white'
) => {
const root = d3.hierarchy(data);
const dx = 10, dy = 159;
const margin = ({top: 10, right: 120, bottom: 10, left: 40});
const diagonal = d3.linkHorizontal().x(d => d.y).y(d => d.x);
const tree = d3.tree().nodeSize([dx, dy]);

Expand Down Expand Up @@ -137,8 +138,6 @@ module.exports = (
if (node.x > right.x) right = node;
});

const height = right.x - left.x + margin.top + margin.bottom;

const transition = svg.transition()
.duration(duration)
.attr('viewBox', [-margin.left, left.x - margin.top, width, height])
Expand Down

0 comments on commit 7e746e8

Please sign in to comment.