// Simple chart mapping content as circles along a time axis. export default function circleChart({svgEl, rootSelection, scale, data = []}) { const t = d => Math.floor(scale(new Date(d.date))) // For force sim beeswarm example, see // http://bl.ocks.org/mbostock/6526445e2b44303eebf21da3b6627320 const collisionForce = forceCollide().radius(d => d.radius + PADDING) const sim = forceSimulation(data) .force('x', forceX(d => d.initialX)) .force('y', forceY(t).strength(1)) .force('collide', collisionForce) .stop() for (let i = 0; i < SIM_STEPS; ++i) sim.tick() const groups = rootSelection.append('g') .selectAll('g.item') .data(data.filter(d => t(d) > 0)) .enter().append('g') .attr('class', 'item') const links = groups.append('a') .attr('xlink:href', d => d.url) .attr('transform', d => `translate(${d.x}, ${d.y})`) .on('mouseover', _ => svgEl.classList.add('tooltipActive')) .on('mouseout', _ => svgEl.classList.remove('tooltipActive')) links.append('circle') .attr('class', d => d.bubbleClass) .attr('r', d => d.radius) const TOOLTIP_TEXT_PADDING = 8 const tooltips = links.append('g').attr('class', 'tooltip') tooltips.append('text') .text(d => { // Manually ellipsis out titles, since we can't really on <text> via css const MAX_LENGTH = 60 return d.title.length > MAX_LENGTH ? `${d.title.slice(0, MAX_LENGTH)}…` : d.title }) .attr('class', 'tooltipText') .attr('text-anchor', 'start') .attr('transform', d => `translate(${TOOLTIP_TEXT_PADDING}, -${d.radius + 35})`) tooltips.append('text') .attr('class', 'date tooltipText') .attr('text-anchor', 'start') .text(d => (new Date(d.date)).toISOString().split('T')[0]) .attr('transform', d => `translate(${TOOLTIP_TEXT_PADDING}, -${d.radius + 20})`) links.append('line') .attr('class', 'tooltipLine') .attr('x1', 1) .attr('x2', 1) .attr('y1', function() { const circle = select(this.parentElement.firstChild) return -1 * (parseFloat(circle.attr('r')) + 3) }) .attr('y2', function() { return parseFloat(select(this).attr('y1')) - 45 }) }
drawChart(nodes, parent) { // transition var t = d3.transition().duration(500); let bubbleGWrapper = d3.select('.bubbleGWrapper') // Apply the general update pattern to the nodes. this.bubbleDataJoin = bubbleGWrapper .selectAll('circle') .data(nodes, d => d.interval) .on('mouseover', d => { console.log('bubbleDataJoin Hover') console.log(d) }); let bubbleDataJoinEnter = this.bubbleDataJoin.enter().append('circle'); this.bubbleDataJoin .transition(t) .style("fill", d => this.seqClr(d.count)) .attr("r", d => d.count); bubbleDataJoinEnter .style("fill", d => this.seqClr(d.count)) .merge(this.bubbleDataJoin) .on('mousemove', d => { let toolTipObj = { val: `${d.index} 1/2 Steps`, count: d.count, pgX: d3.event.pageX, pgY: d3.event.pageY } this.props.showTooltip(toolTipObj); }) .on('mouseout', this.props.hideTooltip) .transition().duration(1200) .attr("r", d => d.count) this.simulation = d3.forceSimulation(nodes) // .force("charge", d3.forceManyBody().strength(-150)) .force("yforce", d3.forceY().strength(.03)) .force("xforce", d3.forceX().strength(.03)) .force("collide", d3.forceCollide().strength(.9).radius(d => d.count + 2)) .force("center", d3.forceCenter()) .alpha(.9) .velocityDecay(.5) .on("tick", () => { this.bubbleDataJoin .attrs({ "cx": d => d.x, "cy": d => d.y }); bubbleDataJoinEnter .attrs({ "cx": d => d.x, "cy": d => d.y }); }); }
.call(d3.zoom().on("zoom", redraw)); let vis = svg .append('svg:g'); function redraw() { vis.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); } let graph = d3.forceSimulation() .force("link", d3.forceLink() .id(d => d.id) .distance(d => d.value / 50)) .force("centre", d3.forceCenter(w / 2, h / 2)) .force("size", d3.forceCollide() .radius(5) .strength(1)) .alphaDecay(0.001) d3.json('data/capital_distances.json', (e, data) => { if (e) throw e // let link = svg.append("g") // .attr("class", "links") // .selectAll("line") // .data(data.links) // .enter() // .append("line") // .attr("stroke-width", d => 5.0 * d.value / 14000)