Skip to content
This repository was archived by the owner on Apr 8, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1335 from shgtkshruch/feat/shinjuku-graph
Browse files Browse the repository at this point in the history
feat: 新宿区の来訪者数の推移グラフを追加
  • Loading branch information
halsk authored Mar 20, 2020
2 parents b858007 + dd07923 commit 970d7bc
Show file tree
Hide file tree
Showing 6 changed files with 352 additions and 5 deletions.
10 changes: 8 additions & 2 deletions components/DataView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
<div class="DataView-CardText">
<slot />
</div>
<div class="DataView-Description">
<slot name="footer-description" />
</div>
<div class="DataView-Footer">
<div class="Footer-Left">
<div>
Expand Down Expand Up @@ -274,8 +277,10 @@ export default Vue.extend({
font-weight: normal;
color: $gray-2;
@include largerThan($large) {
width: 50%;
margin-bottom: 0;
&.with-infoPanel {
width: 50%;
}
}
}
&-CardText {
Expand All @@ -285,7 +290,8 @@ export default Vue.extend({
margin: 10px 0 0;
font-size: 12px;
color: $gray-3;
ul {
ul,
ol {
list-style-type: none;
padding: 0;
}
Expand Down
288 changes: 288 additions & 0 deletions components/VisitorsBarChart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
<template>
<data-view :title="title" :title-id="titleId" :date="date">
<template v-slot:description>
<p :class="$style.Text">
{{
$t(
'2月3日~2月7日の来訪者数 (※1) の平均値 (※2) を 基準としたときの相対値'
)
}}
</p>
<ol>
<li>
{{
$t('※1) ヤフーに蓄積された位置情報データなどを元に算出した参考値')
}}
</li>
<li>{{ $t('※2) 土・日・祝日を除く7:30~8:30の1週間平均値') }}</li>
</ol>
</template>
<bar
:chart-id="chartId"
:chart-data="displayData"
:options="displayOptions"
:height="240"
/>
<template v-slot:footer-description>
<p>
{{ $t('※本データは2020年3月31日までの掲載となります') }}
</p>
<p>
{{ $t('出典') }}:
<a
href="https://ds.yahoo.co.jp/datapolicy/"
target="_blank"
rel="noopenner"
>{{ $t('ヤフー・データソリューション') }}</a
>
</p>
</template>
</data-view>
</template>

<style module lang="scss">
.Text {
margin: 0 !important;
}
</style>

<script lang="ts">
import Vue from 'vue'
import { ThisTypedComponentOptionsWithRecordProps } from 'vue/types/options'
import dayjs from 'dayjs'
import 'dayjs/locale/en'
import weekOfYear from 'dayjs/plugin/weekOfYear'
import updateLocale from 'dayjs/plugin/updateLocale'
import minMax from 'dayjs/plugin/minMax'
import shinjukuData from '@/data/13104_daily_visitors.json'
import DataView from '@/components/DataView.vue'
import { single as color } from '@/utils/colors'
dayjs.extend(updateLocale)
dayjs.extend(weekOfYear)
dayjs.extend(minMax)
dayjs.updateLocale('en', {
weekStart: 1 // 月曜始まり
})
type Data = {}
type Methods = {}
type Computed = {
groupByWeekData: {
[weekNum: number]: typeof shinjukuData.data
}
labels: string[]
standardValue: number
targetData: {
[weekNum: number]: typeof shinjukuData.data
}
targetValues: number[]
displayData: {
labels: string[]
datasets: {
data: number[]
backgroundColor: string
}[]
}
displayOptions: {
responsive: boolean
legend: {
display: boolean
}
scales: {
xAxes: object[]
yAxes: object[]
}
tooltips: {
displayColors: boolean
callbacks: {
title: (tooltipItems: any, data: any) => string
label: (tooltipItems: any, data: any) => string
}
}
}
}
type Props = {
title: string
titleId: string
chartId: string
chartData: typeof shinjukuData.data
date: string
tooltipTitle: (tooltipItems: any, data: any) => string
standardDate: string
startDate: string
}
const options: ThisTypedComponentOptionsWithRecordProps<
Vue,
Data,
Methods,
Computed,
Props
> = {
components: { DataView },
props: {
title: {
type: String,
required: false,
default: ''
},
titleId: {
type: String,
required: false,
default: ''
},
chartId: {
type: String,
required: false,
default: ''
},
chartData: [],
date: {
type: String,
required: false,
default: ''
},
tooltipTitle: {
type: Function,
required: true
},
standardDate: {
type: String,
required: true,
default: ''
},
startDate: {
type: String,
required: true,
default: ''
}
},
computed: {
groupByWeekData() {
const sundays = this.chartData
.map(d => dayjs(d.date))
.filter(date => date.day() === 0)
const latestSunday = dayjs.max(...sundays)
return this.chartData
.filter(d => {
// 休日は除外する
if (d.holiday) return false
// 基準日より前日のデータは除外する
if (dayjs(d.date).isBefore(this.standardDate, 'day')) return false
// 表示期間は直近の日曜日までなので、その日以降のデータは除外する
if (dayjs(d.date).isAfter(latestSunday, 'day')) return false
return true
})
.reduce((res, d) => {
const weekNum = dayjs(d.date).week()
if (!res[weekNum]) res[weekNum] = []
return res[weekNum].push(d) && res
}, {} as any)
},
labels() {
return Object.keys(this.targetData).map((weekNum: any) => {
const start = dayjs(this.startDate)
.week(weekNum)
.startOf('week')
.format('M/D')
const end = dayjs(this.startDate)
.week(weekNum)
.endOf('week')
.format('M/D')
return `${start}~${end}`
})
},
standardValue() {
const standardDays = this.groupByWeekData[dayjs(this.standardDate).week()]
const sum: number = standardDays.reduce(
(sum: number, d: { population: number }) => (sum += d.population),
0
)
return sum / standardDays.length
},
targetData() {
return Object.keys(this.groupByWeekData).reduce((res, weekNum: any) => {
if (dayjs(this.startDate).week() <= weekNum) {
res[weekNum] = this.groupByWeekData[weekNum]
}
return res
}, {} as any)
},
targetValues() {
return Object.values(this.targetData).map((days: any) => {
const sum = days.reduce((sum: number, d: { population: number }) => {
return (sum += d.population)
}, 0)
return sum / days.length
})
},
displayData() {
const percentages = this.targetValues.map(
(val: number) => ((val - this.standardValue) / this.standardValue) * 100
)
return {
labels: this.labels,
datasets: [
{
data: percentages,
backgroundColor: color
}
]
}
},
displayOptions() {
const self = this
return {
responsive: true,
legend: {
display: false
},
tooltips: {
displayColors: false,
callbacks: {
title: self.tooltipTitle,
label(tooltipItem: any) {
const val = tooltipItem.yLabel
return `${val.toFixed(2)}%`
}
}
},
scales: {
xAxes: [
{
gridLines: {
display: false
},
ticks: {
fontSize: 11,
fontColor: '#808080'
}
}
],
yAxes: [
{
ticks: {
fontSize: 11,
fontColor: '#808080',
maxTicksLimit: 8,
suggestedMin: 0,
callback(value: Number) {
return `${value.toFixed(2)}%`
}
}
}
]
}
}
}
}
}
export default Vue.extend(options)
</script>
39 changes: 39 additions & 0 deletions components/cards/ShinjukuVisitorsCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<v-col cols="12" md="6" class="DataCard">
<visitors-bar-chart
:title="$t('新宿区エリアの来訪者推移(参考値)')"
:title-id="'shinjuku-visitors'"
:chart-id="'shinjuku-visitors'"
:chart-data="chartData.data"
:date="chartData.date"
:tooltip-title="tooltipTitle"
:standard-date="'2020-02-03'"
:start-date="'2020-02-10'"
/>
</v-col>
</template>

<script>
import ShinjukuData from '@/data/13104_daily_visitors.json'
import VisitorsBarChart from '@/components/VisitorsBarChart.vue'
export default {
components: {
VisitorsBarChart
},
data() {
// ツールチップ label 文字列
// this.$t を使うため visitors-bar-chart の外側へ
const tooltipTitle = tooltipItems => {
const label = tooltipItems[0].label
return this.$t('期間: {duration}', {
duration: this.$t(label)
})
}
return {
chartData: ShinjukuData,
tooltipTitle
}
}
}
</script>
3 changes: 2 additions & 1 deletion nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ const config: Configuration = {
'/cards/number-of-reports-to-covid19-telephone-advisory-center',
'/cards/number-of-reports-to-covid19-consultation-desk',
'/cards/predicted-number-of-toei-subway-passengers',
'/cards/agency'
'/cards/agency',
'/cards/shinjuku-visitors'
]

const routes: string[] = []
Expand Down
Loading

0 comments on commit 970d7bc

Please sign in to comment.