|
|
|
@ -1,32 +1,79 @@
|
|
|
|
|
<svelte:window on:resize='resize()'/>
|
|
|
|
|
<script>
|
|
|
|
|
import { onMount } from 'svelte';
|
|
|
|
|
import { scaleLinear } from 'd3-scale';
|
|
|
|
|
|
|
|
|
|
export let points;
|
|
|
|
|
|
|
|
|
|
const yTicks = [0, 2, 4, 6, 8];
|
|
|
|
|
const xTicks = [1980, 1990, 2000, 2010];
|
|
|
|
|
const padding = { top: 20, right: 15, bottom: 20, left: 25 };
|
|
|
|
|
|
|
|
|
|
let svg;
|
|
|
|
|
let width = 500;
|
|
|
|
|
let height = 200;
|
|
|
|
|
|
|
|
|
|
let xScale;
|
|
|
|
|
let yScale;
|
|
|
|
|
let minX;
|
|
|
|
|
let maxX;
|
|
|
|
|
let path;
|
|
|
|
|
let area;
|
|
|
|
|
|
|
|
|
|
$: xScale = scaleLinear()
|
|
|
|
|
.domain([minX, maxX])
|
|
|
|
|
.range([padding.left, width - padding.right]);
|
|
|
|
|
|
|
|
|
|
$: yScale = scaleLinear
|
|
|
|
|
.domain([Math.min.apply(null, yTicks), Math.max.apply(null, yTicks)])
|
|
|
|
|
.range([height - padding.bottom, padding.top]);
|
|
|
|
|
|
|
|
|
|
$: minX = points[0].x;
|
|
|
|
|
$: maxX = points[points.length - 1].x;
|
|
|
|
|
$: path = `M${points.map(p => `${xScale(p.x)},${yScale(p.y)}`).join('L')}`;
|
|
|
|
|
$: area = `${path}L${xScale(maxX)},${yScale(0)}L${xScale(minX)},${yScale(0)}Z`;
|
|
|
|
|
|
|
|
|
|
function formatMobile (tick) {
|
|
|
|
|
return "'" + tick % 100;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<div class='chart'>
|
|
|
|
|
function resize() {
|
|
|
|
|
const bcr = svg.getBoundingClientRect();
|
|
|
|
|
width = bcr.width;
|
|
|
|
|
height = bcr.height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMount(resize);
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<svelte:window on:resize='{resize}'/>
|
|
|
|
|
|
|
|
|
|
<div class="chart">
|
|
|
|
|
<h2>Arctic sea ice minimum</h2>
|
|
|
|
|
|
|
|
|
|
<svg ref:svg>
|
|
|
|
|
<!-- y axis -->
|
|
|
|
|
<g class='axis y-axis' transform='translate(0, {padding.top})'>
|
|
|
|
|
<g class="axis y-axis" transform="translate(0, {padding.top})">
|
|
|
|
|
{#each yTicks as tick}
|
|
|
|
|
<g class='tick tick-{tick}' transform='translate(0, {yScale(tick) - padding.bottom})'>
|
|
|
|
|
<line x2='100%'></line>
|
|
|
|
|
<text y='-4'>{tick} {tick === 8 ? ' million sq km' : ''}</text>
|
|
|
|
|
<g class="tick tick-{tick}" transform="translate(0, {yScale(tick) - padding.bottom})">
|
|
|
|
|
<line x2="100%"></line>
|
|
|
|
|
<text y="-4">{tick} {tick === 8 ? ' million sq km' : ''}</text>
|
|
|
|
|
</g>
|
|
|
|
|
{/each}
|
|
|
|
|
</g>
|
|
|
|
|
|
|
|
|
|
<!-- x axis -->
|
|
|
|
|
<g class='axis x-axis'>
|
|
|
|
|
<g class="axis x-axis">
|
|
|
|
|
{#each xTicks as tick}
|
|
|
|
|
<g class='tick tick-{ tick }' transform='translate({xScale(tick)},{height})'>
|
|
|
|
|
<line y1='-{height}' y2='-{padding.bottom}' x1='0' x2='0'></line>
|
|
|
|
|
<text y='-2'>{width > 380 ? tick : formatMobile(tick)}</text>
|
|
|
|
|
<g class="tick tick-{ tick }" transform="translate({xScale(tick)},{height})">
|
|
|
|
|
<line y1="-{height}" y2="-{padding.bottom}" x1="0" x2="0"></line>
|
|
|
|
|
<text y="-2">{width > 380 ? tick : formatMobile(tick)}</text>
|
|
|
|
|
</g>
|
|
|
|
|
{/each}
|
|
|
|
|
</g>
|
|
|
|
|
|
|
|
|
|
<!-- data -->
|
|
|
|
|
<path class='path-area' d='{area}'></path>
|
|
|
|
|
<path class='path-line' d='{path}'></path>
|
|
|
|
|
<path class="path-area" d={area}></path>
|
|
|
|
|
<path class="path-line" d={path}></path>
|
|
|
|
|
</svg>
|
|
|
|
|
|
|
|
|
|
<p>Average September extent. Source: <a href='https://climate.nasa.gov/vital-signs/arctic-sea-ice/'>NSIDC/NASA</a>
|
|
|
|
@ -80,74 +127,3 @@
|
|
|
|
|
fill: rgba(0,100,100,0.2);
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import { scaleLinear } from 'd3-scale';
|
|
|
|
|
|
|
|
|
|
const xScale = scaleLinear();
|
|
|
|
|
const yScale = scaleLinear();
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
padding: { top: 20, right: 15, bottom: 20, left: 25 },
|
|
|
|
|
height: 200,
|
|
|
|
|
width: 500,
|
|
|
|
|
xTicks: [1980, 1990, 2000, 2010],
|
|
|
|
|
yTicks: [0, 2, 4, 6, 8],
|
|
|
|
|
formatMobile(tick) {
|
|
|
|
|
return "'" + tick % 100;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
computed: {
|
|
|
|
|
minX: ({ points }) => {
|
|
|
|
|
return points[0].x;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
maxX: ({ points }) => {
|
|
|
|
|
return points[points.length - 1].x;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
xScale: ({ padding, width, minX, maxX }) => {
|
|
|
|
|
return xScale
|
|
|
|
|
.domain([minX, maxX])
|
|
|
|
|
.range([padding.left, width - padding.right]);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
yScale: ({ padding, height, yTicks }) => {
|
|
|
|
|
return yScale
|
|
|
|
|
.domain([Math.min.apply(null, yTicks), Math.max.apply(null, yTicks)])
|
|
|
|
|
.range([height - padding.bottom, padding.top]);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
path: ({ points, xScale, yScale }) => {
|
|
|
|
|
return 'M' + points
|
|
|
|
|
.map(function (point, i) {
|
|
|
|
|
return xScale(point.x) + ',' + yScale(point.y);
|
|
|
|
|
})
|
|
|
|
|
.join('L');
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
area: ({ points, xScale, yScale, minX, maxX, path }) => {
|
|
|
|
|
return path + (
|
|
|
|
|
'L' + xScale(maxX) + ',' + yScale(0) +
|
|
|
|
|
'L' + xScale(minX) + ',' + yScale(0) +
|
|
|
|
|
'Z'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
oncreate() {
|
|
|
|
|
this.resize();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
|
resize: function () {
|
|
|
|
|
const { width, height } = this.refs.svg.getBoundingClientRect();
|
|
|
|
|
this.set({ width, height });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
</script>
|