checkbox to highlight cases with polarization data
Этот коммит содержится в:
родитель
d0818395a8
Коммит
d983f423a2
@ -22,7 +22,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
display:none;
|
display: none;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +30,7 @@
|
|||||||
display: block;
|
display: block;
|
||||||
width: 15px;
|
width: 15px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
|
margin-top: 3px;
|
||||||
margin-right: 0.4rem;
|
margin-right: 0.4rem;
|
||||||
border: 2px solid var(--usa-blue);
|
border: 2px solid var(--usa-blue);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
|||||||
47
src/components/CheckboxPanel.svelte
Обычный файл
47
src/components/CheckboxPanel.svelte
Обычный файл
@ -0,0 +1,47 @@
|
|||||||
|
<script>
|
||||||
|
import { highlightPolarization } from '../stores/filters';
|
||||||
|
|
||||||
|
import Checkbox from './Checkbox.svelte';
|
||||||
|
|
||||||
|
function handleClick(type) {
|
||||||
|
switch (type) {
|
||||||
|
case 'polarization':
|
||||||
|
$highlightPolarization = !$highlightPolarization;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul class="checkboxpanel-wrapper">
|
||||||
|
<li>
|
||||||
|
<Checkbox id="checkboxpanel-checkbox-polarization"
|
||||||
|
checked={$highlightPolarization}
|
||||||
|
on:click={() => handleClick('polarization')}>
|
||||||
|
<span>Highlight cases with polarization data</span>
|
||||||
|
</Checkbox>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding: 0.4rem 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 0 0 0.5rem;
|
||||||
|
font-family: var(--font-02);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--usa-blue);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -11,12 +11,14 @@
|
|||||||
textSearchFilter,
|
textSearchFilter,
|
||||||
selectAllFilters,
|
selectAllFilters,
|
||||||
contextData,
|
contextData,
|
||||||
originalTimeDomain } from '../stores/filters';
|
originalTimeDomain,
|
||||||
|
highlightPolarization } from '../stores/filters';
|
||||||
import { timeScale, attributionScoreScale } from '../stores/scales';
|
import { timeScale, attributionScoreScale } from '../stores/scales';
|
||||||
|
|
||||||
import Dropdown from './Dropdown.svelte';
|
import Dropdown from './Dropdown.svelte';
|
||||||
import Slider from './Slider.svelte';
|
import Slider from './Slider.svelte';
|
||||||
import SearchText from './SearchText.svelte';
|
import SearchText from './SearchText.svelte';
|
||||||
|
import CheckboxPanel from './CheckboxPanel.svelte';
|
||||||
import Share from './Share.svelte';
|
import Share from './Share.svelte';
|
||||||
|
|
||||||
export let timePoints;
|
export let timePoints;
|
||||||
@ -32,6 +34,7 @@
|
|||||||
function handleButtonClick() {
|
function handleButtonClick() {
|
||||||
selectAllFilters();
|
selectAllFilters();
|
||||||
contextData.unselectAll();
|
contextData.unselectAll();
|
||||||
|
$highlightPolarization = false;
|
||||||
if ($originalTimeDomain) {
|
if ($originalTimeDomain) {
|
||||||
$timeScale.domain($originalTimeDomain);
|
$timeScale.domain($originalTimeDomain);
|
||||||
$timeScale = $timeScale;
|
$timeScale = $timeScale;
|
||||||
@ -89,6 +92,9 @@
|
|||||||
Reset
|
Reset
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="checkbox-panel">
|
||||||
|
<CheckboxPanel />
|
||||||
|
</div>
|
||||||
<Share />
|
<Share />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@ -56,16 +56,18 @@
|
|||||||
|
|
||||||
<div class="polarization-strip"
|
<div class="polarization-strip"
|
||||||
bind:clientWidth={width}>
|
bind:clientWidth={width}>
|
||||||
<svg class="pol-magnifier"
|
{#if (width > 0)}
|
||||||
width={width}
|
<svg class="pol-magnifier"
|
||||||
height={magnifierHeight}>
|
width={width}
|
||||||
<path d={line(leftPathData)} />
|
height={magnifierHeight}>
|
||||||
<path d={line(rightPathData)} />
|
<path d={line(leftPathData)} />
|
||||||
<text x={Math.max(15, valueWidth / 2)}
|
<path d={line(rightPathData)} />
|
||||||
y={yScale(1)}>
|
<text x={Math.max(15, valueWidth / 2)}
|
||||||
{Math.round(engagementExplained * 100)}%
|
y={yScale(1)}>
|
||||||
</text>
|
{Math.round(engagementExplained * 100)}%
|
||||||
</svg>
|
</text>
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
<div class="pol-layer-wrapper">
|
<div class="pol-layer-wrapper">
|
||||||
{#each categories as category (category.id)}
|
{#each categories as category (category.id)}
|
||||||
<div class="pol-layer pol-{category.id}"
|
<div class="pol-layer pol-{category.id}"
|
||||||
|
|||||||
@ -10,7 +10,8 @@
|
|||||||
attributionScoreDef,
|
attributionScoreDef,
|
||||||
textSearchFilter,
|
textSearchFilter,
|
||||||
originalTimeDomain,
|
originalTimeDomain,
|
||||||
contextData } from '../stores/filters';
|
contextData,
|
||||||
|
highlightPolarization } from '../stores/filters';
|
||||||
import { urlFromFilters } from '../utils/share';
|
import { urlFromFilters } from '../utils/share';
|
||||||
|
|
||||||
import Icon from 'svelte-awesome';
|
import Icon from 'svelte-awesome';
|
||||||
@ -37,7 +38,8 @@
|
|||||||
$attributionScoreFilter,
|
$attributionScoreFilter,
|
||||||
$textSearchFilter,
|
$textSearchFilter,
|
||||||
$contextData,
|
$contextData,
|
||||||
caseId);
|
caseId,
|
||||||
|
$highlightPolarization);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="share">
|
<div class="share">
|
||||||
|
|||||||
@ -35,8 +35,15 @@
|
|||||||
originalTimeDomain,
|
originalTimeDomain,
|
||||||
contextData,
|
contextData,
|
||||||
caseIdFilter,
|
caseIdFilter,
|
||||||
tagFilter } from '../stores/filters';
|
tagFilter,
|
||||||
import { haveOverlap, withinRange, includesTextSearch, isCaseId, preloadImages } from '../utils/misc';
|
highlightPolarization } from '../stores/filters';
|
||||||
|
import {
|
||||||
|
haveOverlap,
|
||||||
|
withinRange,
|
||||||
|
includesTextSearch,
|
||||||
|
isCaseId,
|
||||||
|
showPolarization,
|
||||||
|
preloadImages } from '../utils/misc';
|
||||||
import { selected } from '../stores/eventSelections';
|
import { selected } from '../stores/eventSelections';
|
||||||
import { drawWrapper } from '../stores/elements';
|
import { drawWrapper } from '../stores/elements';
|
||||||
|
|
||||||
@ -134,6 +141,7 @@
|
|||||||
$attributionScoreFilter = urlFilters.attributionScores;
|
$attributionScoreFilter = urlFilters.attributionScores;
|
||||||
$textSearchFilter = urlFilters.textSearch;
|
$textSearchFilter = urlFilters.textSearch;
|
||||||
$caseIdFilter = urlFilters.caseId;
|
$caseIdFilter = urlFilters.caseId;
|
||||||
|
$highlightPolarization = urlFilters.highlightPolarization;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -203,6 +211,7 @@
|
|||||||
&& includesTextSearch($textSearchFilter, d.search)
|
&& includesTextSearch($textSearchFilter, d.search)
|
||||||
&& withinRange($attributionScoreFilter, d.attributionScore)
|
&& withinRange($attributionScoreFilter, d.attributionScore)
|
||||||
&& isCaseId($caseIdFilter, d.id)
|
&& isCaseId($caseIdFilter, d.id)
|
||||||
|
&& showPolarization($highlightPolarization, d.polarization)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -94,3 +94,5 @@ export const brushed = writable(false);
|
|||||||
export const originalTimeDomain = writable(null);
|
export const originalTimeDomain = writable(null);
|
||||||
|
|
||||||
export const caseIdFilter = writable();
|
export const caseIdFilter = writable();
|
||||||
|
|
||||||
|
export const highlightPolarization = writable(false);
|
||||||
|
|||||||
@ -53,6 +53,12 @@ export const includesTextSearch = (filter, s) => {
|
|||||||
// check if case id filter is set and if id is matching
|
// check if case id filter is set and if id is matching
|
||||||
export const isCaseId = (filter, id) => filter === undefined ? true : (filter === id);
|
export const isCaseId = (filter, id) => filter === undefined ? true : (filter === id);
|
||||||
|
|
||||||
|
// check, if polarization data can be shown
|
||||||
|
export const showPolarization = (filter, polarization) => {
|
||||||
|
if (!filter) return(true);
|
||||||
|
return(polarization.fulfills10Articles || polarization.fulfills25Percent);
|
||||||
|
};
|
||||||
|
|
||||||
// extract filter items from data
|
// extract filter items from data
|
||||||
export const extractFilterCategories = (data, name) =>
|
export const extractFilterCategories = (data, name) =>
|
||||||
uniq(data.map((d) => d[name]).flat());
|
uniq(data.map((d) => d[name]).flat());
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export const baseUrl = 'https://interference2020.org';
|
// export const baseUrl = 'https://interference2020.org';
|
||||||
// export const baseUrl = 'http://localhost:5000';
|
export const baseUrl = 'http://localhost:5000';
|
||||||
|
|
||||||
export const urlFromFilters = (disinformantNations,
|
export const urlFromFilters = (disinformantNations,
|
||||||
platforms,
|
platforms,
|
||||||
@ -10,15 +10,17 @@ export const urlFromFilters = (disinformantNations,
|
|||||||
attributionScores,
|
attributionScores,
|
||||||
textSearch,
|
textSearch,
|
||||||
contextData,
|
contextData,
|
||||||
caseId = '') => {
|
caseId = '',
|
||||||
|
highlightPolarization) => {
|
||||||
const params = {
|
const params = {
|
||||||
ts: encodeURIComponent(textSearch),
|
ts: encodeURIComponent(textSearch),
|
||||||
as: [attributionScores[0], attributionScores[1]].join(';'),
|
as: [attributionScores[0], attributionScores[1]].join(';'),
|
||||||
f: filtersToHex([disinformantNations, platforms, methods, sources, sourceCategories, tags, contextData]),
|
f: filtersToHex([disinformantNations, platforms, methods, sources, sourceCategories, tags, contextData]),
|
||||||
id: caseId
|
id: caseId,
|
||||||
|
bool: filtersToBin([highlightPolarization])
|
||||||
};
|
};
|
||||||
|
|
||||||
return `${baseUrl}/#${params.f}-${params.id}-${params.ts}-${params.as}`;
|
return `${baseUrl}/#${params.f}-${params.id}-${params.ts}-${params.as}-${params.bool}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filtersToHex = (arr) => {
|
export const filtersToHex = (arr) => {
|
||||||
@ -26,6 +28,11 @@ export const filtersToHex = (arr) => {
|
|||||||
return hex;
|
return hex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const filtersToBin = (arr) => {
|
||||||
|
const bin = arr.map((d) => d ? 1 : 0).join('');
|
||||||
|
return bin;
|
||||||
|
};
|
||||||
|
|
||||||
export const binaryToHex = (binary) => parseInt(binary , 2).toString(16).toLowerCase();
|
export const binaryToHex = (binary) => parseInt(binary , 2).toString(16).toLowerCase();
|
||||||
|
|
||||||
export const hexToBinary = (hex) => parseInt(hex, 16).toString(2);
|
export const hexToBinary = (hex) => parseInt(hex, 16).toString(2);
|
||||||
@ -34,7 +41,9 @@ export const binaryToBool = (binary) => binary.split('').map((d) => d === '0' ?
|
|||||||
|
|
||||||
export const parseUrl = (hash) => {
|
export const parseUrl = (hash) => {
|
||||||
const s = hash.substring(1);
|
const s = hash.substring(1);
|
||||||
const [ disinformantNations, platforms, methods, sources, sourceCategories, tags, contextData, caseId, textSearch, attributionScores] = s.split('-');
|
const [ disinformantNations, platforms, methods, sources, sourceCategories, tags, contextData, caseId, textSearch, attributionScores, bools] = s.split('-');
|
||||||
|
|
||||||
|
const boolArray = bools.split('').map((d) => +d === 1 ? true : false);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
disinformantNations: binaryToBool(hexToBinary(disinformantNations)),
|
disinformantNations: binaryToBool(hexToBinary(disinformantNations)),
|
||||||
@ -46,6 +55,7 @@ export const parseUrl = (hash) => {
|
|||||||
contextData: binaryToBool(hexToBinary(contextData)),
|
contextData: binaryToBool(hexToBinary(contextData)),
|
||||||
caseId: caseId === '' ? undefined : +caseId,
|
caseId: caseId === '' ? undefined : +caseId,
|
||||||
textSearch: decodeURIComponent(textSearch),
|
textSearch: decodeURIComponent(textSearch),
|
||||||
attributionScores: attributionScores.split(';').map((d) => +d)
|
attributionScores: attributionScores.split(';').map((d) => +d),
|
||||||
|
highlightPolarization: boolArray[0]
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Загрузка…
x
Ссылка в новой задаче
Block a user