polarization data visualized
Этот коммит содержится в:
родитель
06ef9c3806
Коммит
d8d77a137a
@ -141,6 +141,36 @@ a:hover, span.pseudolink:hover {
|
||||
background-color: #e24545a1;
|
||||
}
|
||||
|
||||
/* polarization */
|
||||
.pol-l {
|
||||
background-color: #2e64a0;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.pol-ll {
|
||||
background-color: #61a3de;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.pol-c {
|
||||
background-color: #96659e;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.pol-lr {
|
||||
background-color: #a15552;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.pol-r {
|
||||
background-color: #ca0800;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.pol-undef {
|
||||
background-color: #e0d3e2;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* the landing page */
|
||||
.page-wrapper {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
import { width, panelHeight, controlsHeight } from '../stores/dimensions';
|
||||
import { tooltip } from '../stores/eventSelections';
|
||||
import { fade, slide } from 'svelte/transition';
|
||||
import { timeFormat, format } from 'd3';
|
||||
import { timeFormat } from 'd3';
|
||||
import { extractHostname } from '../utils/misc';
|
||||
import {
|
||||
platformFilter,
|
||||
@ -20,6 +20,8 @@
|
||||
import EventTooltipCross from './EventTooltipCross.svelte';
|
||||
import ScoreBar from './ScoreBar.svelte';
|
||||
import ScoreQuestions from './ScoreQuestions.svelte';
|
||||
import ImpactStrip from './ImpactStrip.svelte';
|
||||
import PolarizationLegend from './PolarizationLegend.svelte';
|
||||
import Share from './Share.svelte';
|
||||
|
||||
const offset = {
|
||||
@ -32,7 +34,6 @@
|
||||
|
||||
const attributionTf = timeFormat('%B %d, %Y');
|
||||
const activityTf = timeFormat('%B %Y');
|
||||
const commaFormat = format(',');
|
||||
|
||||
let elem;
|
||||
let tWidth, tHeight;
|
||||
@ -181,19 +182,19 @@
|
||||
<p>pending</p>
|
||||
{:else}
|
||||
<ul>
|
||||
<li>
|
||||
<span class="smi-score facebook">{commaFormat($tooltip.tp.smiFacebook)}</span>
|
||||
<span class="smi-label">Facebook</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="smi-score twitter">{commaFormat($tooltip.tp.smiTwitter)}</span>
|
||||
<span class="smi-label">Twitter</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="smi-score reddit">{commaFormat($tooltip.tp.smiReddit)}</span>
|
||||
<span class="smi-label">Reddit</span>
|
||||
</li>
|
||||
<ImpactStrip value={$tooltip.tp.smiFacebook}
|
||||
polarization={$tooltip.tp.polarization}
|
||||
label="Facebook" />
|
||||
<ImpactStrip value={$tooltip.tp.smiTwitter}
|
||||
polarization={$tooltip.tp.polarization}
|
||||
label="Twitter" />
|
||||
<ImpactStrip value={$tooltip.tp.smiReddit}
|
||||
polarization={$tooltip.tp.polarization}
|
||||
label="Reddit" />
|
||||
</ul>
|
||||
{#if ($tooltip.tp.polarization.fulfills10Articles || $tooltip.tp.polarization.fulfills25Percent)}
|
||||
<PolarizationLegend />
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{#if ($tooltip.tp.imageUrl)}
|
||||
@ -426,26 +427,6 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.smi li {
|
||||
margin: 0.2rem 0.3rem 0.2rem 0;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.smi-score {
|
||||
padding: 0 0.2rem;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.07),
|
||||
0 2px 4px rgba(0,0,0,0.07);
|
||||
}
|
||||
|
||||
.smi-label {
|
||||
display: inline-block;
|
||||
padding: 0 0.1rem;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
@ -458,11 +439,6 @@
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.no-break {
|
||||
word-break: keep-all;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.scroll-wrapper .image {
|
||||
min-height: 1%;
|
||||
width: 100%;
|
||||
|
||||
52
src/components/ImpactStrip.svelte
Обычный файл
52
src/components/ImpactStrip.svelte
Обычный файл
@ -0,0 +1,52 @@
|
||||
<script>
|
||||
import { format } from 'd3';
|
||||
|
||||
import PolarizationStrip from './PolarizationStrip.svelte';
|
||||
|
||||
export let value = 0;
|
||||
export let polarization;
|
||||
export let label = '';
|
||||
|
||||
const commaFormat = format(',');
|
||||
|
||||
let valueWidth = 0;
|
||||
</script>
|
||||
|
||||
<li>
|
||||
<div class="smi-score {label.toLowerCase()}"
|
||||
bind:clientWidth={valueWidth}>
|
||||
{commaFormat(value)}
|
||||
</div>
|
||||
<span class="smi-label">
|
||||
{label}
|
||||
</span>
|
||||
{#if ((polarization.fulfills10Articles || polarization.fulfills25Percent) && value > 0)}
|
||||
<PolarizationStrip polarization={polarization[label.toLowerCase()]}
|
||||
smi={value}
|
||||
valueWidth={valueWidth} />
|
||||
{/if}
|
||||
</li>
|
||||
|
||||
<style>
|
||||
li {
|
||||
margin: 0.2rem 0.3rem 0.2rem 0;
|
||||
font-size: 0.8rem;
|
||||
min-width: 30%;
|
||||
}
|
||||
|
||||
.smi-score {
|
||||
display: inline-block;
|
||||
padding: 0 0.2rem;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07),
|
||||
0 2px 4px rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
|
||||
.smi-label {
|
||||
display: inline-block;
|
||||
padding: 0 0.1rem;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
</style>
|
||||
52
src/components/PolarizationLegend.svelte
Обычный файл
52
src/components/PolarizationLegend.svelte
Обычный файл
@ -0,0 +1,52 @@
|
||||
<script>
|
||||
import { categories } from '../inputs/polarization';
|
||||
</script>
|
||||
|
||||
<div class="pol-legend">
|
||||
<p>Polarization:</p>
|
||||
<ul>
|
||||
{#each categories as category (category)}
|
||||
<li>
|
||||
<div class="pol-legend-field pol-{category.id}"></div>
|
||||
<p>{category.name}</p>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.pol-legend {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: var(--font-02);
|
||||
color: var(--dfrlab-gray);
|
||||
}
|
||||
|
||||
.pol-legend p {
|
||||
margin-right: 0.7rem;
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.pol-legend ul {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.pol-legend ul li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pol-legend ul li p {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.pol-legend-field {
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
</style>
|
||||
108
src/components/PolarizationStrip.svelte
Обычный файл
108
src/components/PolarizationStrip.svelte
Обычный файл
@ -0,0 +1,108 @@
|
||||
<script>
|
||||
import { categories } from '../inputs/polarization';
|
||||
|
||||
import { scaleLinear, line as d3line, curveBasis } from 'd3';
|
||||
|
||||
export let polarization;
|
||||
export let smi = 0;
|
||||
export let valueWidth = 0;
|
||||
|
||||
const magnifierHeight = 20;
|
||||
|
||||
const margin = {
|
||||
top: 4,
|
||||
right: 2,
|
||||
bottom: 0,
|
||||
left: 2
|
||||
};
|
||||
|
||||
const yScale = scaleLinear()
|
||||
.domain([0, 1])
|
||||
.range([margin.top, magnifierHeight - margin.bottom]);
|
||||
|
||||
const line = d3line()
|
||||
.x((d) => d[0])
|
||||
.y((d) => yScale(d[1]))
|
||||
.curve(curveBasis);
|
||||
|
||||
let width;
|
||||
let stack = {};
|
||||
|
||||
$: totalEngagement = Object.keys(polarization).map((k) => polarization[k]).reduce((acc, cur) => acc + cur);
|
||||
$: engagementExplained = totalEngagement / smi;
|
||||
|
||||
$: Object.keys(polarization).forEach((k) => {
|
||||
const value = polarization[k];
|
||||
stack[k] = {
|
||||
value,
|
||||
width: Math.floor(100 * value / totalEngagement, 2)
|
||||
};
|
||||
});
|
||||
|
||||
$: leftPathData = [
|
||||
[margin.left + valueWidth / 2 - engagementExplained * valueWidth / 2, 0],
|
||||
[margin.left + valueWidth / 2 - engagementExplained * valueWidth / 2, 0.3],
|
||||
[margin.left, 0.7],
|
||||
[margin.left, 1]
|
||||
];
|
||||
|
||||
$: rightPathData = [
|
||||
[valueWidth / 2 + engagementExplained * valueWidth / 2 - margin.right, 0],
|
||||
[valueWidth / 2 + engagementExplained * valueWidth / 2 - margin.right, 0.3],
|
||||
[width * 0.98 - margin.right, 0.7],
|
||||
[width * 0.98 - margin.right, 1]
|
||||
];
|
||||
</script>
|
||||
|
||||
<div class="polarization-strip"
|
||||
bind:clientWidth={width}>
|
||||
<svg class="pol-magnifier"
|
||||
width={width}
|
||||
height={magnifierHeight}>
|
||||
<path d={line(leftPathData)} />
|
||||
<path d={line(rightPathData)} />
|
||||
<text x={valueWidth / 2}
|
||||
y={yScale(1)}>
|
||||
{Math.round(engagementExplained * 100)}%
|
||||
</text>
|
||||
</svg>
|
||||
<div class="pol-layer-wrapper">
|
||||
{#each categories as category (category.id)}
|
||||
<div class="pol-layer pol-{category.id}"
|
||||
style="width: {stack[category.id].width}%;">
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.polarization-strip {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
path {
|
||||
stroke: var(--dfrlab-gray);
|
||||
stroke-width: 1.5;
|
||||
stroke-dasharray: 2 3;
|
||||
stroke-linecap: round;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
text {
|
||||
font-family: var(--font-02);
|
||||
font-size: 0.6rem;
|
||||
text-anchor: middle;
|
||||
fill: var(--dfrlab-gray);
|
||||
}
|
||||
|
||||
.pol-layer-wrapper {
|
||||
width: 100%;
|
||||
height: 1rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.pol-layer {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
22
src/inputs/polarization.js
Обычный файл
22
src/inputs/polarization.js
Обычный файл
@ -0,0 +1,22 @@
|
||||
export const categories = [
|
||||
{
|
||||
id: 'l',
|
||||
name: 'left'
|
||||
},
|
||||
{
|
||||
id: 'll',
|
||||
name: 'leanleft'
|
||||
},
|
||||
{
|
||||
id: 'c',
|
||||
name: 'center'
|
||||
},
|
||||
{
|
||||
id: 'lr',
|
||||
name: 'leanright'
|
||||
},
|
||||
{
|
||||
id: 'r',
|
||||
name: 'right'
|
||||
},
|
||||
];
|
||||
@ -92,21 +92,21 @@ const loadData = async () => {
|
||||
lr: +d.allsides_engagments_leanright,
|
||||
r: +d.allsides_engagments_right
|
||||
},
|
||||
fb: {
|
||||
facebook: {
|
||||
l: +d.allsides_engagments_left_facebook,
|
||||
ll: +d.allsides_engagments_leanleft_facebook,
|
||||
c: +d.allsides_engagments_center_facebook,
|
||||
lr: +d.allsides_engagments_leanright_facebook,
|
||||
r: +d.allsides_engagments_right_facebook
|
||||
},
|
||||
tw: {
|
||||
twitter: {
|
||||
l: +d.allsides_engagments_left_twitter,
|
||||
ll: +d.allsides_engagments_leanleft_twitter,
|
||||
c: +d.allsides_engagments_center_twitter,
|
||||
lr: +d.allsides_engagments_leanright_twitter,
|
||||
r: +d.allsides_engagments_right_twitter
|
||||
},
|
||||
re: {
|
||||
reddit: {
|
||||
l: +d.allsides_engagments_left_reddit,
|
||||
ll: +d.allsides_engagments_leanleft_reddit,
|
||||
c: +d.allsides_engagments_center_reddit,
|
||||
|
||||
Загрузка…
x
Ссылка в новой задаче
Block a user