Skip to content

Commit

Permalink
convert beeswarm to functional component
Browse files Browse the repository at this point in the history
  • Loading branch information
tevko committed Nov 26, 2024
1 parent c4a1239 commit 6bef2c7
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 102 deletions.
6 changes: 3 additions & 3 deletions client-report/src/COMPONENT_TEMPLATE.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ class ComponentName extends React.Component {
};
}
render() {
const styles = this.getStyles();
console.log(styles)
const { base } = this.getStyles();
const styles = Object.assign({}, base, this.props.style);
return (
<div>
<div style={styles}>
{"ComponentName"}
</div>
);
Expand Down
188 changes: 91 additions & 97 deletions client-report/src/components/beeswarm/beeswarm.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (C) 2012-present, The Authors. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

import React from "react";
import React, { useState, useEffect } from "react";
import CommentList from "../lists/commentList";
import * as globals from "../globals";
import _ from "lodash";
Expand Down Expand Up @@ -44,11 +44,11 @@ import _ from "lodash";
// }


class VoronoiCells extends React.Component {
const VoronoiCells = ({ currentBeeswarmComment, voronoi, onHoverCallback }) => {

/* https://bl.ocks.org/mbostock/6526445e2b44303eebf21da3b6627320 */

getFill(cell) {
const getFill = (cell) => {

/* find the index of cell.data.tid in probabilitiesTids and use the index of it as the accessor */

Expand All @@ -58,7 +58,7 @@ class VoronoiCells extends React.Component {
// // !this.props.probabilitiesTids
// ) {
// return
if (this.props.currentBeeswarmComment && this.props.currentBeeswarmComment.tid === cell.data.tid) {
if (currentBeeswarmComment?.tid === cell.data.tid) {
return "rgb(255,0,0)";
} else {
return "black"
Expand All @@ -78,19 +78,18 @@ class VoronoiCells extends React.Component {
// }
}

render() {

return (
<g>
{
this.props.voronoi.map((cell, i) => {
voronoi.map((cell, i) => {
return (
<g key={i} onMouseEnter={this.props.onHoverCallback(cell)}>
<g key={i} onMouseEnter={onHoverCallback(cell)}>
<path fill="none" style={{pointerEvents: "all"}} d={"M" + cell.join("L") + "Z"}/>

<circle
r={3}
fill={this.getFill(cell)}
fill={getFill(cell)}
cx={cell.data.x}
cy={cell.data.y}
/>
Expand All @@ -100,107 +99,103 @@ class VoronoiCells extends React.Component {
}
</g>
)
}
}

class Beeswarm extends React.Component {
constructor(props) {
super(props);

this.svgWidth = 960;
this.svgHeight = 200;
this.margin = {top: 10, right: 10, bottom: 10, left: 10};
this.widthMinusMargins = 960 - this.margin.left - this.margin.right;
this.heightMinusMargins = 200 - this.margin.top - this.margin.bottom;

this.state = {
currentBeeswarmComment: null,
commentsWithExtremity: null,
axesRendered: false,
};
}
onHoverCallback(d) {
const Beeswarm = ({ comments, extremity, probabilitiesTids, probabilities, conversation, ptptCount, math, formatTid, voteColors }) => {

const svgWidth = 960;
const svgHeight = 200;
const margin = {top: 10, right: 10, bottom: 10, left: 10};
const widthMinusMargins = 960 - margin.left - margin.right;
const heightMinusMargins = 200 - margin.top - margin.bottom;

const [currentBeeswarmComment, setCurrentBeeswarmComment] = useState(null);
const [commentsWithExtremity, setCommentsWithExtremity] = useState(null);
const [x, setX] = useState(null);
const [axesRendered, setAxesRendered] = useState(false);
const[vor, setVoronoi] = useState(null);

const onHoverCallback = (d) => {
return () => {
this.setState({currentBeeswarmComment: d.data});
setCurrentBeeswarmComment(d.data);
}
}

componentDidMount() {
const setup = () => {
const commentsWithExtremityPlaceHolder = [];
_.each(comments, (comment) => {
if (extremity[comment.tid] > 0) {
const cwe = Object.assign({}, comment, {extremity: extremity[comment.tid]});
commentsWithExtremityPlaceHolder.push(cwe)
}
})

var x = d3.scaleLinear()
.rangeRound([0, widthMinusMargins]);

x.domain(d3.extent(commentsWithExtremityPlaceHolder, function(d) { return d.extremity; }));

var simulation = d3.forceSimulation(commentsWithExtremityPlaceHolder)
.force("x", d3.forceX(function(d) {
return x(d.extremity);
}).strength(1))
.force("y", d3.forceY(heightMinusMargins / 2))
.force("collide", d3.forceCollide(4))
.stop();

for (var i = 0; i < 120; ++i) simulation.tick();

const voronoi = d3.voronoi()
.extent([[-margin.left, -margin.top], [widthMinusMargins + margin.right, heightMinusMargins + margin.top]])
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.polygons(commentsWithExtremityPlaceHolder)

// if (!this.state.axesRendered) {
// d3.select("#beeswarmAxisAttachPointD3").append("g")
// .attr("class", "axis axis--x")
// .attr("transform", "translate(0," + this.heightMinusMargins + ")")
// .call(d3.axisBottom(x).ticks(3));
// }

setX(x);
setVoronoi(voronoi);
setCommentsWithExtremity(commentsWithExtremityPlaceHolder);
setAxesRendered(true);
}

useEffect(() => {
if (
this.props.comments &&
this.props.extremity &&
!this.state.commentsWithExtremity /* if we poll, change this so it is auto updating */
comments &&
extremity &&
commentsWithExtremity /* if we poll, change this so it is auto updating */
) {
this.setup();
setup();
}
}
setup () {
const commentsWithExtremity = [];
_.each(this.props.comments, (comment) => {
if (this.props.extremity[comment.tid] > 0) {
const cwe = Object.assign({}, comment, {extremity: this.props.extremity[comment.tid]});
commentsWithExtremity.push(cwe)
}
})

var x = d3.scaleLinear()
.rangeRound([0, this.widthMinusMargins]);

x.domain(d3.extent(commentsWithExtremity, function(d) { return d.extremity; }));

var simulation = d3.forceSimulation(commentsWithExtremity)
.force("x", d3.forceX(function(d) {
return x(d.extremity);
}).strength(1))
.force("y", d3.forceY(this.heightMinusMargins / 2))
.force("collide", d3.forceCollide(4))
.stop();

for (var i = 0; i < 120; ++i) simulation.tick();

const voronoi = d3.voronoi()
.extent([[-this.margin.left, -this.margin.top], [this.widthMinusMargins + this.margin.right, this.heightMinusMargins + this.margin.top]])
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.polygons(commentsWithExtremity)

// if (!this.state.axesRendered) {
// d3.select("#beeswarmAxisAttachPointD3").append("g")
// .attr("class", "axis axis--x")
// .attr("transform", "translate(0," + this.heightMinusMargins + ")")
// .call(d3.axisBottom(x).ticks(3));
// }

this.setState({
x,
voronoi,
commentsWithExtremity,
axesRendered: true
})
}
render() {
}, []);

return (
<div style={{width: this.svgWidth}}>
<div style={{width: svgWidth}}>
<p style={globals.primaryHeading}> How divisive was the conversation? </p>
<p style={globals.paragraph}>
Statements (here as little circles) to the left were voted on the same way—either everyone agreed or everyone disagreed. Statements to the right were divisive—participants were split between agreement and disagreement.
</p>
<p style={globals.paragraph}>
<strong>How to use this:</strong> Hover to see the statement text. Start on the far right to find out what the most divisive statement was.
</p>
<svg width={this.svgWidth} height={this.svgHeight}>
<g id="beeswarmAxisAttachPointD3" transform={"translate(" + this.margin.left + "," + this.margin.top + ")"}>
<svg width={svgWidth} height={svgHeight}>
<g id="beeswarmAxisAttachPointD3" transform={"translate(" + margin.left + "," + margin.top + ")"}>
{
this.state.commentsWithExtremity ?
commentsWithExtremity ?
<VoronoiCells
probabilitiesTids={this.props.probabilitiesTids}
probabilities={this.state.currentBeeswarmComment ? this.props.probabilities[this.state.currentBeeswarmComment.tid] : null}
currentBeeswarmComment={this.state.currentBeeswarmComment}
voronoi={this.state.voronoi}
onHoverCallback={this.onHoverCallback.bind(this)}/> : null
probabilitiesTids={probabilitiesTids}
probabilities={currentBeeswarmComment ? probabilities[this.state.currentBeeswarmComment.tid] : null}
currentBeeswarmComment={currentBeeswarmComment}
voronoi={vor}
onHoverCallback={onHoverCallback}/> : null
}
</g>
<line x1="0" y1={this.svgHeight - 10} x2={this.svgWidth} y2={this.svgHeight - 10} strokeWidth="1" stroke="black"/>
<line x1="0" y1={svgHeight - 10} x2={svgWidth} y2={svgHeight - 10} strokeWidth="1" stroke="black"/>
</svg>
<div style={{display: "flex", justifyContent: "space-between", margin: 0}}>
<p style={{margin: 0}}> Consensus statements </p>
Expand All @@ -209,22 +204,21 @@ class Beeswarm extends React.Component {
{/*<ProbabilityLegend/>*/}

<div style={{minHeight: "140px", paddingTop: "20px"}}>
{ this.state.currentBeeswarmComment ?
{ currentBeeswarmComment ?

<CommentList
conversation={this.props.conversation}
ptptCount={this.props.ptptCount}
math={this.props.math}
formatTid={this.props.formatTid}
tidsToRender={[this.state.currentBeeswarmComment.tid]}
comments={this.props.comments}
voteColors={this.props.voteColors}/> : null
conversation={conversation}
ptptCount={ptptCount}
math={math}
formatTid={formatTid}
tidsToRender={[currentBeeswarmComment.tid]}
comments={comments}
voteColors={voteColors}/> : null
}
</div>

</div>
);
}
}

export default Beeswarm;
Expand Down
5 changes: 3 additions & 2 deletions client-report/src/components/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class Comment extends React.Component {
render() {
// const showAsAnon = !this.props.comment.social || this.props.comment.anon || this.props.comment.is_seed;

const styles = Object.assign({}, globals.paragraph, {fontStyle: "italic"});

return (
<Flex
styleOverrides={{
Expand All @@ -52,8 +54,7 @@ class Comment extends React.Component {
{this.props.formatTid(this.props.comment.tid)}
</span>
<span style={{fontWeight: 700, fontStyle: "auto"}}>{this.props.comment.is_meta ? "Metadata: " : ''}</span>
{/* style={[globals.paragraph, {fontStyle: "italic"}]} */}
<span >{ this.props.comment.txt }</span>
<span style={styles}>{ this.props.comment.txt }</span>
</Flex>
<svg width={globals.barChartWidth} height={70}>
<line
Expand Down

0 comments on commit 6bef2c7

Please sign in to comment.