Timeline edits
Этот коммит содержится в:
родитель
85e95811ff
Коммит
f75f12e940
@ -1,50 +1,87 @@
|
||||
<script>
|
||||
import { scaleUtc } from 'd3-scale';
|
||||
import { scaleUtc, scalePoint, scaleOrdinal } from 'd3-scale';
|
||||
import { extent } from 'd3-array';
|
||||
import { utcFormat } from 'd3-time-format';
|
||||
import { fade } from 'svelte/transition'
|
||||
|
||||
export let cases;
|
||||
|
||||
const margins = {
|
||||
top: 24,
|
||||
right: 24,
|
||||
bottom: 24,
|
||||
left: 24
|
||||
bottom: 38,
|
||||
left: 120
|
||||
};
|
||||
|
||||
let width;
|
||||
let height = 120;
|
||||
let height = 280;
|
||||
|
||||
$: dateExtent = extent(cases.map((d) => new Date(d.attribution_date)));
|
||||
|
||||
$: xScale = scaleUtc(dateExtent, [0, width - margins.right - margins.left]);
|
||||
$: ticks = xScale.ticks(5);
|
||||
|
||||
const actorNations = ['China', 'Iran', 'North Korea', 'Russia'];
|
||||
const colors = ['#0f4c8a', '#8a0f8a', '#8a4d0f', '#0f8a0f'];
|
||||
|
||||
let yScale = scalePoint(actorNations, [height - margins.bottom - margins.top, 0]).padding(1);
|
||||
let colorScale = scaleOrdinal(actorNations, colors);
|
||||
</script>
|
||||
|
||||
<div class="timeline-container" bind:clientWidth={width}>
|
||||
<svg {width} {height}>
|
||||
{#if xScale}
|
||||
<g transform={`translate(${margins.left},${margins.top})`}>
|
||||
<line x1={0} x2={width} y1={0} y2={0} stroke={'#000000'} stroke-width={2}></line>
|
||||
<!--line
|
||||
x1={0}
|
||||
x2={width}
|
||||
y1={height - margins.bottom - margins.top}
|
||||
y2={height - margins.bottom - margins.top}
|
||||
stroke={'#000000'}
|
||||
stroke-width={2}
|
||||
></line-->
|
||||
{#each actorNations as nation}
|
||||
<line
|
||||
x1={0}
|
||||
x2={width}
|
||||
y1={yScale(nation)}
|
||||
y2={yScale(nation)}
|
||||
style:stroke={colorScale(nation)}
|
||||
stroke-width={2}
|
||||
opacity={0.3}
|
||||
></line>
|
||||
<text
|
||||
class="country-label"
|
||||
x={-10}
|
||||
y={yScale(nation) + 4}
|
||||
text-anchor={"end"}
|
||||
fill={colorScale(nation)}
|
||||
>{nation}</text>
|
||||
{/each}
|
||||
{#each ticks as tick}
|
||||
<line
|
||||
x1={xScale(tick)}
|
||||
x2={xScale(tick)}
|
||||
y1={0}
|
||||
y2={12}
|
||||
stroke={'#000000'}
|
||||
stroke-width={2}
|
||||
y1={height - margins.bottom - margins.top}
|
||||
y2={height - margins.bottom - margins.top + 10}
|
||||
stroke={'#bbbbbb'}
|
||||
stroke-width={1}
|
||||
></line>
|
||||
<text x={xScale(tick)} y={32} text-anchor={'middle'}>{utcFormat('%b %d')(tick)}</text>
|
||||
<text
|
||||
class="time-axis-tick-label"
|
||||
x={xScale(tick)}
|
||||
y={height - margins.bottom - margins.top + 24}
|
||||
text-anchor={'middle'}>{utcFormat('%b')(tick)}</text
|
||||
>
|
||||
{/each}
|
||||
{#each cases as attrCase}
|
||||
{#if attrCase.show}
|
||||
<a href={'#case-' + attrCase.attribution_id}>
|
||||
<a href={'#case-' + attrCase.attribution_id} transition:fade>
|
||||
<circle
|
||||
cx={xScale(new Date(attrCase.attribution_date))}
|
||||
cy={0}
|
||||
cy={yScale(attrCase.actor_nation[0])}
|
||||
r={6}
|
||||
fill={'#000000'}
|
||||
style:fill={colorScale(attrCase.actor_nation[0])}
|
||||
stroke={'#ffffff'}
|
||||
stroke-width={2}
|
||||
></circle>
|
||||
@ -60,4 +97,12 @@
|
||||
.timeline-container {
|
||||
width: 100%;
|
||||
}
|
||||
.country-label {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.time-axis-tick-label {
|
||||
font-size: 0.8rem;
|
||||
fill: #888888;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
methodFilter.init(cases, 'methods')
|
||||
$attributionScoreFilter = attributionScoreDef;
|
||||
|
||||
//console.log(cases.map(d => d.attribution_date))
|
||||
console.log(cases.map(d => d.campaign))
|
||||
});
|
||||
|
||||
$: if (cases) {
|
||||
@ -104,8 +104,8 @@
|
||||
<div class="container">
|
||||
<div class="field has-addons">
|
||||
<div class="buttons has-addons">
|
||||
<button class={displayDataAs == "Table" ? "button is-success is-selected" : "button"} on:click={() => {displayDataAs = "Table"}}>Table</button>
|
||||
<button class={displayDataAs == "Cards" ? "button is-success is-selected" : "button"} on:click={() => {displayDataAs = "Cards"}}>Cards</button>
|
||||
<button class={displayDataAs == "Table" ? "button is-dark is-selected is-small" : "button is-small"} on:click={() => {displayDataAs = "Table"}}>Table</button>
|
||||
<button class={displayDataAs == "Cards" ? "button is-dark is-selected is-small" : "button is-small"} on:click={() => {displayDataAs = "Cards"}}>Cards</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Загрузка…
x
Ссылка в новой задаче
Block a user