├── .DS_Store
├── .gitignore
├── LICENSE
├── README.md
├── data_processing.py
├── demo
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── 5.png
├── 6.png
└── 7.png
├── music_people_processing.py
├── music_processing.py
├── people_processing.py
├── scrapy
├── .DS_Store
├── 0_filter_movie.py
├── music_run.sh
├── people_run.sh
├── run.sh
├── scrapy.cfg
└── tutorial
│ ├── .DS_Store
│ ├── __init__.py
│ ├── items.py
│ ├── pipelines.py
│ ├── settings.py
│ └── spiders
│ ├── __init__.py
│ ├── music.py
│ ├── people.py
│ └── spider.py
├── server.py
├── static
├── Thumbs.db
├── color.png
├── color_ko.png
├── insight.png
├── insight_ko.png
├── logo.png
├── main.png
├── main2.png
├── materialize.min.css
├── music.js
├── music_color.png
├── music_color_ko.png
├── music_logo.png
├── screenshot.png
├── script.js
├── style.css
├── weight.png
└── weight_ko.png
└── templates
├── index.html
├── layout.html
└── music.html
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.tar*
3 | *.jar
4 | *.json
5 | *.sql
6 | *.sqlite3
7 |
8 | # Created by https://www.gitignore.io
9 |
10 | #!! ERROR: py is undefined. Use list command to see defined gitignore types !!#
11 |
12 | ### Python ###
13 | # Byte-compiled / optimized / DLL files
14 | __pycache__/
15 | *.py[cod]
16 |
17 | # C extensions
18 | *.so
19 |
20 | # Distribution / packaging
21 | .Python
22 | env/
23 | build/
24 | develop-eggs/
25 | dist/
26 | downloads/
27 | eggs/
28 | lib/
29 | lib64/
30 | parts/
31 | sdist/
32 | var/
33 | *.egg-info/
34 | .installed.cfg
35 | *.egg
36 |
37 | # PyInstaller
38 | # Usually these files are written by a python script from a template
39 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
40 | *.manifest
41 | *.spec
42 |
43 | # Installer logs
44 | pip-log.txt
45 | pip-delete-this-directory.txt
46 |
47 | # Unit test / coverage reports
48 | htmlcov/
49 | .tox/
50 | .coverage
51 | .cache
52 | nosetests.xml
53 | coverage.xml
54 |
55 | # Translations
56 | *.mo
57 | *.pot
58 |
59 | # Django stuff:
60 | *.log
61 |
62 | # Sphinx documentation
63 | docs/_build/
64 |
65 | # PyBuilder
66 | target/
67 |
68 |
69 | ### vim ###
70 | [._]*.s[a-w][a-z]
71 | [._]s[a-w][a-z]
72 | *.un~
73 | Session.vim
74 | .netrwhist
75 | *~
76 |
77 |
78 | ### Django ###
79 | *.log
80 | *.pot
81 | *.pyc
82 | __pycache__/
83 | local_settings.py
84 |
85 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 by Taehoon Kim.
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above
13 | copyright notice, this list of conditions and the following
14 | disclaimer in the documentation and/or other materials provided
15 | with the distribution.
16 |
17 | * The names of the contributors may not be used to endorse or
18 | promote products derived from this software without specific
19 | prior written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | VoxOffice
2 | =========
3 |
4 | A Data Visualization of Box office history. [link](http://pail.unist.ac.kr/carpedm20/vox/)
5 |
6 |
7 | Screenshot
8 | ----------
9 |
10 | 
11 | 
12 | 
13 |
14 |
15 | VoxMusic
16 | =========
17 |
18 | A Data Visualization of Music chart history. [link](http://pail.unist.ac.kr/carpedm20/music/)
19 |
20 |
21 | 
22 | 
23 | 
24 |
25 | Copyright
26 | ---------
27 |
28 | Copyright :copyright: 2015 [Kim Tae Hoon](carpedm20.github.io)
29 |
30 | The MIT License (MIT)
31 |
--------------------------------------------------------------------------------
/data_processing.py:
--------------------------------------------------------------------------------
1 | import json
2 | import numpy as np
3 | from bs4 import BeautifulSoup
4 | import requests
5 | from collections import defaultdict
6 |
7 | MAX_RANK = 10
8 | SKIP_DATE = 7
9 |
10 | for genre in ['action', 'comedy', 'thriller', 'romance', 'all']:
11 | print " ******** %s ********* " % genre
12 |
13 | j = json.loads(open('static/movie-%s.json' % genre).read())
14 |
15 | years = range(2007, 2015)
16 |
17 | poster_dict = {}
18 |
19 | def poster_url(code):
20 | b = BeautifulSoup(requests.get('http://movie.naver.com/movie/bi/mi/photoViewPopup.nhn?movieCode='+str(code)).text)
21 | try:
22 | img = b.find('img')
23 | return [img['src']+"?type=m203_290_2", img['alt']]
24 | except:
25 | return ['http://static.naver.net/movie/2012/06/dft_img203x290.png','']
26 |
27 | for year in years:
28 | print year
29 |
30 | movies = defaultdict(int)
31 | dates = defaultdict(int)
32 |
33 | movie_title = {}
34 |
35 | start_year = '%s0101' % year
36 | end_year = '%s1231' % year
37 |
38 | for i in j:
39 | dd = int(i['date'][-2:])
40 | if dd % SKIP_DATE == 0 or dd in [28,29,30,31]:
41 | if start_year < i['date'] < end_year:
42 | if i['rank'] > MAX_RANK:
43 | continue
44 | url = i['url']
45 | code = int(url[url.index('code=')+5:])
46 | movies[code] += 1
47 | movie_title[code] = i['name']
48 | dates[i['date']] += 1
49 |
50 | movies_key = movies.keys()
51 | movies_key.sort()
52 |
53 | dates = dates.keys()
54 | dates.sort()
55 |
56 | print "Distinct movies : %s" % len(movies_key)
57 | print "Distinct dates : %s" % len(dates)
58 |
59 | y1 = np.zeros((len(movies_key),len(dates)), dtype='int16')
60 |
61 | new_movie_title = {}
62 |
63 | movies_key = [i[0] for i in sorted(movies.iteritems(), key=lambda (k,v): v,reverse=True)]
64 |
65 | for i in j:
66 | dd = int(i['date'][-2:])
67 | if dd % SKIP_DATE == 0 or dd in [28,29,30,31]:
68 | if start_year < i['date'] < end_year:
69 | url = i['url']
70 | code = int(url[url.index('code=')+5:])
71 | try:
72 | url = poster_dict[code]
73 | except:
74 | url = poster_dict[code] = poster_url(code)
75 | try:
76 | new_code = movies_key.index(code)
77 | except:
78 | continue
79 | date = dates.index(i['date'])
80 | new_movie_title[new_code] = [code, url, movie_title[code]]
81 | y1[new_code][date] = int(i['rank'])
82 |
83 | ans = {'movies' : new_movie_title,
84 | 'mindate' : dates[0],
85 | 'maxdate' : dates[-1],
86 | 'skipdate' : SKIP_DATE,
87 | 'y1' : y1.tolist() }
88 |
89 | with open('%s-%s.json' % (genre, year),'w') as f:
90 | json.dump(ans, f)
91 |
--------------------------------------------------------------------------------
/demo/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/demo/1.png
--------------------------------------------------------------------------------
/demo/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/demo/2.png
--------------------------------------------------------------------------------
/demo/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/demo/3.png
--------------------------------------------------------------------------------
/demo/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/demo/4.png
--------------------------------------------------------------------------------
/demo/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/demo/5.png
--------------------------------------------------------------------------------
/demo/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/demo/6.png
--------------------------------------------------------------------------------
/demo/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/demo/7.png
--------------------------------------------------------------------------------
/music_people_processing.py:
--------------------------------------------------------------------------------
1 | #-*- coding: utf-8 -*-
2 | import json
3 | import numpy as np
4 | from bs4 import BeautifulSoup
5 | import requests
6 | from collections import defaultdict
7 |
8 | MAX_RANK = 20
9 |
10 | #for chart_type in ['total', 'domestic', 'oversea']:
11 | chart_type = 'total'
12 | j = json.loads(open('scrapy/music_%s.json' % chart_type).read())
13 |
14 | artist_name = {}
15 |
16 | for i in j:
17 | code = i['artist_id']
18 | if code != -1:
19 | artist_name[i['artist']] = code
20 |
21 | for year in xrange(2008, 2015):
22 | print year
23 |
24 | artists = defaultdict(int)
25 | dates = defaultdict(int)
26 |
27 | artist_id = {}
28 | artist = {}
29 |
30 | start_year = '%s0101' % year
31 | end_year = '%s1231' % year
32 |
33 | for i in j:
34 | dd = int(i['date'][:4])
35 | if dd == year:
36 | code = i['artist_id']
37 |
38 | if i['rank'] > MAX_RANK:
39 | continue
40 |
41 | if code == -1:
42 | try:
43 | code = i['artist_id'] = artist_name[i['artist']]
44 | except:
45 | try:
46 | item = [item for item in artist_name.items() if i['artist'][:-2] in item[0]][0]
47 | code = item[1]
48 | except:
49 | if i['artist'] == u'HIGH4':
50 | code = i['artist_id'] = 326950
51 | elif i['artist'] == u'신용재(포맨)':
52 | code = i['artist_id'] = 125963
53 |
54 | if code == -1:
55 | continue
56 |
57 | artists[code] += 1
58 |
59 | artist[code] = i['artist']
60 | artist_id[code] = i['artist_id']
61 |
62 | dates[int(i['date'])] += 1
63 |
64 | artists_key = artists.keys()
65 | artists_key.sort()
66 |
67 | dates = dates.keys()
68 | dates.sort()
69 |
70 | print "Distinct artists : %s" % len(artists_key)
71 | print "Distinct dates : %s" % len(dates)
72 |
73 | y1 = np.zeros((len(artists_key),len(dates)), dtype='int16')
74 |
75 | new_music_title = {}
76 |
77 | artists_key = [i[0] for i in sorted(artists.iteritems(), key=lambda (k,v): v,reverse=True)]
78 |
79 | for i in j:
80 | dd = int(i['date'][:4])
81 | if dd == year:
82 | code = i['artist_id']
83 |
84 | if i['rank'] > MAX_RANK:
85 | continue
86 | if i['artist'] == u'Various Artists':
87 | continue
88 |
89 | try:
90 | new_code = artists_key.index(code)
91 | except:
92 | continue
93 |
94 | date = dates.index(int(i['date']))
95 | new_music_title[new_code] = [code, artist[code] ]
96 |
97 | tmp = y1[new_code][date]
98 |
99 | if tmp == 0:
100 | y1[new_code][date] = int(i['rank'])
101 | else:
102 | if (int(i['rank']) > tmp):
103 | pass
104 |
105 | if y1[new_code][date]:
106 | pass
107 | #print y1[new_code][date]
108 |
109 | ans = {'musics' : new_music_title,
110 | 'y1' : y1.tolist() }
111 |
112 | with open('artist-%s.json' % (year),'w') as f:
113 | json.dump(ans, f)
114 |
--------------------------------------------------------------------------------
/music_processing.py:
--------------------------------------------------------------------------------
1 | import json
2 | import numpy as np
3 | from bs4 import BeautifulSoup
4 | import requests
5 | from collections import defaultdict
6 |
7 | MAX_RANK = 10
8 |
9 | for chart_type in ['total', 'domestic', 'oversea']:
10 | print " ******** %s ********* " % chart_type
11 |
12 | j = json.loads(open('scrapy/music_%s.json' % chart_type).read())
13 |
14 | for year in xrange(2008, 2015):
15 | print year
16 |
17 | musics = defaultdict(int)
18 | dates = defaultdict(int)
19 |
20 | music_title = {}
21 | album_id = {}
22 | artist_id = {}
23 | track_id = {}
24 | artist = {}
25 |
26 | start_year = '%s0101' % year
27 | end_year = '%s1231' % year
28 |
29 | for i in j:
30 | dd = int(i['date'][:4])
31 | if dd == year:
32 | if i['rank'] > MAX_RANK:
33 | continue
34 | code = i['track_id']
35 | musics[code] += 1
36 | music_title[code] = i['name']
37 | album_id[code] = i['album_id']
38 | artist_id[code] = i['artist_id']
39 | artist[code] = i['artist']
40 | track_id[code] = i['track_id']
41 | dates[int(i['date'])] += 1
42 |
43 | musics_key = musics.keys()
44 | musics_key.sort()
45 |
46 | dates = dates.keys()
47 | dates.sort()
48 |
49 | print "Distinct musics : %s" % len(musics_key)
50 | print "Distinct dates : %s" % len(dates)
51 |
52 | y1 = np.zeros((len(musics_key),len(dates)), dtype='int16')
53 |
54 | new_music_title = {}
55 |
56 | musics_key = [i[0] for i in sorted(musics.iteritems(), key=lambda (k,v): v,reverse=True)]
57 |
58 | for i in j:
59 | dd = int(i['date'][:4])
60 | if dd == year:
61 | code = i['track_id']
62 |
63 | try:
64 | new_code = musics_key.index(code)
65 | except:
66 | continue
67 |
68 | date = dates.index(int(i['date']))
69 | new_music_title[new_code] = [code,
70 | music_title[code],
71 | artist[code],
72 | album_id[code],
73 | artist_id[code],
74 | track_id[code],
75 | ]
76 | y1[new_code][date] = int(i['rank'])
77 |
78 | ans = {'musics' : new_music_title,
79 | 'y1' : y1.tolist() }
80 |
81 | with open('%s-%s.json' % (chart_type, year),'w') as f:
82 | json.dump(ans, f)
83 |
--------------------------------------------------------------------------------
/people_processing.py:
--------------------------------------------------------------------------------
1 | import json
2 | import numpy as np
3 | from bs4 import BeautifulSoup
4 | import requests
5 | from collections import defaultdict
6 |
7 | MAX_RANK = 10
8 | SKIP_DATE = 7
9 |
10 | j = json.loads(open('static/people.json').read())
11 |
12 | years = range(2007, 2015)
13 |
14 | poster_dict = {}
15 |
16 | def poster_url(code):
17 | b = BeautifulSoup(requests.get('http://movie.naver.com/movie/bi/pi/basic.nhn?st=1&code='+str(code)).text)
18 | try:
19 | img = b.findAll('div', {'class':'poster'})[0].find('img')
20 | src = img.attrs['src']
21 | src = src[src.find('&q=')+3:]
22 | print src, img.attrs['alt']
23 | return [src, img.attrs['alt']]
24 | except:
25 | return ['http://static.naver.net/movie/2012/06/dft_img111x139.png','']
26 |
27 | for year in years:
28 | print year
29 |
30 | movies = defaultdict(int)
31 | dates = defaultdict(int)
32 |
33 | movie_title = {}
34 |
35 | start_year = '%s0101' % year
36 | end_year = '%s1231' % year
37 |
38 | for i in j:
39 | dd = int(i['date'][-2:])
40 | if dd % SKIP_DATE == 0 or dd in [28,29,30,31]:
41 | if start_year < i['date'] < end_year:
42 | if i['rank'] > MAX_RANK:
43 | continue
44 | url = i['url']
45 | code = int(url[url.index('code=')+5:])
46 | movies[code] += 1
47 | movie_title[code] = i['name']
48 | dates[i['date']] += 1
49 |
50 | movies_key = movies.keys()
51 | movies_key.sort()
52 |
53 | dates = dates.keys()
54 | dates.sort()
55 |
56 | print "Distinct movies : %s" % len(movies_key)
57 | print "Distinct dates : %s" % len(dates)
58 |
59 | y1 = np.zeros((len(movies_key),len(dates)), dtype='int16')
60 |
61 | new_movie_title = {}
62 |
63 | movies_key = [i[0] for i in sorted(movies.iteritems(), key=lambda (k,v): v,reverse=True)]
64 |
65 | for i in j:
66 | dd = int(i['date'][-2:])
67 | if dd % SKIP_DATE == 0 or dd in [28,29,30,31]:
68 | if start_year < i['date'] < end_year:
69 | url = i['url']
70 | code = int(url[url.index('code=')+5:])
71 | try:
72 | url = poster_dict[code]
73 | except:
74 | url = poster_dict[code] = poster_url(code)
75 | try:
76 | new_code = movies_key.index(code)
77 | except:
78 | continue
79 | date = dates.index(i['date'])
80 | new_movie_title[new_code] = [code, url, movie_title[code]]
81 | y1[new_code][date] = int(i['rank'])
82 |
83 | ans = {'movies' : new_movie_title,
84 | 'mindate' : dates[0],
85 | 'maxdate' : dates[-1],
86 | 'skipdate' : SKIP_DATE,
87 | 'y1' : y1.tolist() }
88 |
89 | with open('people-%s.json' % (year),'w') as f:
90 | json.dump(ans, f)
91 |
--------------------------------------------------------------------------------
/scrapy/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/scrapy/.DS_Store
--------------------------------------------------------------------------------
/scrapy/0_filter_movie.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import json
3 | import sys
4 |
5 | if len(sys.argv) < 2:
6 | print "Error: need 1 argument"
7 | sys.exit(1)
8 |
9 | f=open(sys.argv[1], 'r')
10 | j=json.loads(f.read())
11 | f.close()
12 |
13 | movie_dict = {}
14 |
15 | for idx, i in enumerate(j):
16 | print "[%s/%s] %s. %s" % (idx, len(j), i['rank'], i['name'])
17 |
18 | i_copy = i.copy()
19 | i_copy.pop('date')
20 |
21 | try:
22 | ovie_dict[i['date']].append(i_copy)
23 | except:
24 | movie_dict[i['date']] = [i_copy]
25 |
26 | f_name = "filtered_%s" % sys.argv[1]
27 |
28 | f=open(f_name, 'w')
29 | json.dump(movie_dict, f)
30 | f.close()
31 |
32 | print "Finished!"
33 |
--------------------------------------------------------------------------------
/scrapy/music_run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #mode = TOTAL, DOMESTIC, OVERSEA
3 | scrapy crawl music -a mode=TOTAL -o music_total.json
4 | scrapy crawl music -a mode=DOMESTIC -o music_domestic.json
5 | scrapy crawl music -a mode=OVERSEA -o music_oversea.json
6 |
--------------------------------------------------------------------------------
/scrapy/people_run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | scrapy crawl people -o people.json
3 |
--------------------------------------------------------------------------------
/scrapy/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | for i in 0 1 2 3 4 5 6 7 8 10 11 12 13 14 15 16 17 18 19
3 | do
4 | scrapy crawl rank -a tg=$i -o movie$i.json
5 | done
6 |
--------------------------------------------------------------------------------
/scrapy/scrapy.cfg:
--------------------------------------------------------------------------------
1 | # Automatically created by: scrapy startproject
2 | #
3 | # For more information about the [deploy] section see:
4 | # http://doc.scrapy.org/en/latest/topics/scrapyd.html
5 |
6 | [settings]
7 | default = tutorial.settings
8 |
9 | [deploy]
10 | #url = http://localhost:6800/
11 | project = tutorial
12 |
--------------------------------------------------------------------------------
/scrapy/tutorial/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/scrapy/tutorial/.DS_Store
--------------------------------------------------------------------------------
/scrapy/tutorial/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/scrapy/tutorial/__init__.py
--------------------------------------------------------------------------------
/scrapy/tutorial/items.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Define here the models for your scraped items
4 | #
5 | # See documentation in:
6 | # http://doc.scrapy.org/en/latest/topics/items.html
7 |
8 | import scrapy
9 |
10 |
11 | class TutorialItem(scrapy.Item):
12 | # define the fields for your item here like:
13 | # name = scrapy.Field()
14 | pass
15 |
--------------------------------------------------------------------------------
/scrapy/tutorial/pipelines.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Define your item pipelines here
4 | #
5 | # Don't forget to add your pipeline to the ITEM_PIPELINES setting
6 | # See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
7 |
8 |
9 | class TutorialPipeline(object):
10 | def process_item(self, item, spider):
11 | return item
12 |
--------------------------------------------------------------------------------
/scrapy/tutorial/settings.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Scrapy settings for tutorial project
4 | #
5 | # For simplicity, this file contains only the most important settings by
6 | # default. All the other settings are documented here:
7 | #
8 | # http://doc.scrapy.org/en/latest/topics/settings.html
9 | #
10 |
11 | BOT_NAME = 'tutorial'
12 |
13 | SPIDER_MODULES = ['tutorial.spiders']
14 | NEWSPIDER_MODULE = 'tutorial.spiders'
15 |
16 | # Crawl responsibly by identifying yourself (and your website) on the user-agent
17 | #USER_AGENT = 'tutorial (+http://www.yourdomain.com)'
18 |
--------------------------------------------------------------------------------
/scrapy/tutorial/spiders/__init__.py:
--------------------------------------------------------------------------------
1 | # This package will contain the spiders of your Scrapy project
2 | #
3 | # Please refer to the documentation for information on how to create and manage
4 | # your spiders.
5 |
--------------------------------------------------------------------------------
/scrapy/tutorial/spiders/music.py:
--------------------------------------------------------------------------------
1 | __author__ = 'carpedm20'
2 | __date__ = '2014.07.25'
3 |
4 | from scrapy.spider import BaseSpider
5 |
6 | # http://music.naver.com/listen/history/index.nhn?type=TOTAL&year=2008&month=01&week=3
7 |
8 | from scrapy.item import Item, Field
9 |
10 | class Music(Item):
11 | name = Field()
12 | artist = Field()
13 | artist_id = Field()
14 | track_id = Field()
15 | album_id = Field()
16 | rank = Field()
17 | date = Field()
18 |
19 | #tgs = range(20)
20 | #tgs.remove(9)
21 |
22 | def make_urls(mode = "TOTAL"):
23 | # mode = TOTAL, DOMESTIC, OVERSEA
24 | base = "http://music.naver.com/listen/history/index.nhn?type=%s&year=%s&month=%s&week=%s"
25 | urls = []
26 |
27 | for year in xrange(2008, 2015):
28 | for month in xrange(1, 13):
29 | for week in xrange(1,5):
30 | url = base % (mode, year, month, week)
31 |
32 | urls.append(url)
33 |
34 | print "[*] length of urls : %s" % len(urls)
35 |
36 | return urls
37 |
38 | import re
39 | import urlparse
40 |
41 | class RankSpider(BaseSpider):
42 | name = "music"
43 | allowed_domains = ["movie.naver.com"]
44 | start_urls = None
45 |
46 | def __init__(self, mode="TOTAL"):
47 | self.start_urls = make_urls(mode)
48 |
49 | def parse(self, response):
50 | parsed = urlparse.urlparse(response.url)
51 | dic = urlparse.parse_qs(parsed.query)
52 |
53 | date = dic['year'][0] + dic['month'][0] + dic['week'][0]
54 |
55 | items = []
56 |
57 | hrefs = response.xpath("//tbody/tr/td[@class='title']/a/@href").extract()
58 | titles = response.xpath("//tbody/tr/td[@class='name']//span[@class='ellipsis']/text()").extract()
59 |
60 | for idx, elem in enumerate(response.xpath("//tbody/tr")[1:]):
61 | music = elem.xpath("./td[@class='name']")
62 |
63 | href = music.xpath("./a/@href")[0].extract()
64 | album_id = int(re.findall(r'\d+',href)[0])
65 |
66 | href = music.xpath("./a/@href")[-1].extract()
67 | track_id = int(re.findall(r'\d+',href)[0])
68 |
69 | artist = elem.xpath("./td[@class='_artist artist']")
70 |
71 | if len(artist) == 0:
72 | artist = elem.xpath("./td[@class='_artist artist no_ell2']")
73 | artist_id = -1
74 |
75 | artist_name = artist.xpath("./a/text()")[0].extract()
76 | else:
77 | try:
78 | href = artist.xpath("./a/@href")[0].extract()
79 | artist_id = int(href[href.find('artistId=')+9:])
80 |
81 | artist_name = artist.xpath("./a/span/text()")[0].extract().strip()
82 | except:
83 | artist_name = artist.xpath("./span/span/text()")[0].extract().strip()
84 | artist_id = -1
85 |
86 | try:
87 | music_name = music.xpath("./a/span/text()")[0].extract()
88 | except:
89 | music_name = music.xpath("./span/span/text()")[0].extract()
90 | #print idx
91 |
92 | music= Music()
93 | music['name'] = music_name
94 | music['artist'] = artist_name
95 | music['artist_id'] = artist_id
96 | music['track_id'] = track_id
97 | music['album_id'] = album_id
98 | music['rank'] = idx + 1
99 | music['date'] = date
100 |
101 | items.append(music)
102 |
103 | return items
104 |
--------------------------------------------------------------------------------
/scrapy/tutorial/spiders/people.py:
--------------------------------------------------------------------------------
1 | __author__ = 'carpedm20'
2 | __date__ = '2014.07.25'
3 |
4 | from scrapy.spider import BaseSpider
5 |
6 | # http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=20050207&tg=0
7 |
8 | from scrapy.item import Item, Field
9 |
10 | class Movie(Item):
11 | name = Field()
12 | url = Field()
13 | rank = Field()
14 | date = Field()
15 |
16 | #tgs = range(20)
17 | #tgs.remove(9)
18 |
19 | def make_urls():
20 | #url = "http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=%s&tg=%s"
21 | url = "http://movie.naver.com/movie/sdb/rank/rpeople.nhn?date=%s"
22 | urls = []
23 |
24 | from datetime import date, timedelta
25 |
26 | current_date = date(2005, 2, 7)
27 | end_date = date.today()
28 | delta = timedelta(days=1)
29 |
30 | while current_date <= end_date:
31 | urls.append(url % (current_date.strftime("%Y%m%d")))
32 | current_date += delta
33 |
34 | print "[*] length of urls : %s" % len(urls)
35 |
36 | return urls
37 |
38 | import urlparse
39 |
40 | class RankSpider(BaseSpider):
41 | name = "people"
42 | allowed_domains = ["movie.naver.com"]
43 | start_urls = None
44 |
45 | def __init__(self):
46 | self.start_urls = make_urls()
47 |
48 | def parse(self, response):
49 | parsed = urlparse.urlparse(response.url)
50 | date = urlparse.parse_qs(parsed.query)['date']
51 |
52 | items = []
53 |
54 | hrefs = response.xpath("//tbody/tr/td[@class='title']/a/@href").extract()
55 | titles = response.xpath("//tbody/tr/td[@class='title']/a/text()").extract()
56 |
57 | for index, href in enumerate(hrefs):
58 | movie = Movie()
59 | movie['url'] = href
60 | movie['name'] = titles[index]
61 | movie['rank'] = index + 1
62 | movie['date'] = date[0]
63 | items.append(movie)
64 |
65 | return items
66 |
--------------------------------------------------------------------------------
/scrapy/tutorial/spiders/spider.py:
--------------------------------------------------------------------------------
1 | __author__ = 'carpedm20'
2 | __date__ = '2014.07.25'
3 |
4 | from scrapy.spider import BaseSpider
5 | from scrapy.selector import HtmlXPathSelector
6 |
7 | # http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=20050207&tg=0
8 |
9 | from scrapy.item import Item, Field
10 |
11 | class Movie(Item):
12 | name = Field()
13 | url = Field()
14 | rank = Field()
15 | date = Field()
16 |
17 | #tgs = range(20)
18 | #tgs.remove(9)
19 |
20 | def make_urls(tg):
21 | url = "http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=%s&tg=%s"
22 | urls = []
23 |
24 | from datetime import date, timedelta
25 |
26 | current_date = date(2005, 2, 7)
27 | end_date = date.today()
28 | delta = timedelta(days=1)
29 |
30 | while current_date <= end_date:
31 | urls.append(url % (current_date.strftime("%Y%m%d"), tg))
32 | current_date += delta
33 |
34 | print "[*] length of urls : %s" % len(urls)
35 |
36 | return urls
37 |
38 | import urlparse
39 |
40 | class RankSpider(BaseSpider):
41 | name = "rank"
42 | allowed_domains = ["movie.naver.com"]
43 | start_urls = None
44 |
45 | def __init__(self, tg='0'):
46 | self.tg = tg
47 | self.start_urls = make_urls(self.tg)
48 |
49 | def parse(self, response):
50 | parsed = urlparse.urlparse(response.url)
51 | date = urlparse.parse_qs(parsed.query)['date']
52 |
53 | hxs = HtmlXPathSelector(response)
54 | items = []
55 |
56 | hrefs = hxs.xpath("//tbody/tr/td/div/a/@href").extract()
57 | titles = hxs.xpath("//tbody/tr/td/div/a/text()").extract()
58 |
59 | for index, href in enumerate(hrefs):
60 | movie = Movie()
61 | movie['url'] = href
62 | movie['name'] = titles[index]
63 | movie['rank'] = index + 1
64 | movie['date'] = date[0]
65 | items.append(movie)
66 |
67 | return items
68 |
--------------------------------------------------------------------------------
/server.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask import url_for, redirect, render_template
3 | app = Flask(__name__, static_url_path="/carpedm20/vox/static",)
4 |
5 | import re
6 | from glob import glob
7 |
8 | PREFIX = "carpedm20/"
9 | STATIC = "%sstatic" % PREFIX
10 |
11 | @app.route('/')
12 | @app.route('/carpedm20/')
13 | def root():
14 | return redirect(url_for('index'))
15 |
16 | @app.route('/carpedm20/vox/')
17 | def index():
18 | global PREFIX, STATIC
19 |
20 | years = glob("./static/all-*.json")
21 | years = [re.findall(r'\d+',year)[0] for year in years]
22 | years.sort(reverse=True)
23 |
24 | return render_template('index.html', years = years,
25 | fb_href = "http://pail.unist.ac.kr/carpedm20/vox/",
26 | body_class = 'yir-generic',
27 | nav_bar_class = 'nav-bar',
28 | footer = 'darken-1')
29 |
30 | @app.route('/carpedm20/music/')
31 | def music():
32 | global PREFIX, STATIC
33 |
34 | years = glob("./static/total-*.json")
35 | years = [re.findall(r'\d+',year)[0] for year in years]
36 | years.sort(reverse=True)
37 |
38 | return render_template('music.html', years = years,
39 | fb_href = "http://pail.unist.ac.kr/carpedm20/music/",
40 | body_class = 'yir-generic-music',
41 | nav_bar_class = 'nav-bar-music',
42 | footer = 'lighten-2')
43 |
44 | if __name__ == '__main__':
45 | app.run(host='0.0.0.0', debug=True, port=5000)
46 |
--------------------------------------------------------------------------------
/static/Thumbs.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/Thumbs.db
--------------------------------------------------------------------------------
/static/color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/color.png
--------------------------------------------------------------------------------
/static/color_ko.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/color_ko.png
--------------------------------------------------------------------------------
/static/insight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/insight.png
--------------------------------------------------------------------------------
/static/insight_ko.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/insight_ko.png
--------------------------------------------------------------------------------
/static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/logo.png
--------------------------------------------------------------------------------
/static/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/main.png
--------------------------------------------------------------------------------
/static/main2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/main2.png
--------------------------------------------------------------------------------
/static/music.js:
--------------------------------------------------------------------------------
1 | window.mobilecheck = function() {
2 | var check = false;
3 | (function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
4 | return check;
5 | }
6 |
7 | if (window.mobilecheck()) {
8 | alert("VoxMusic은 모바일 브라우저를 지원하지 않습니다");
9 | }
10 |
11 | progressJs().start();
12 |
13 | current_section = 3;
14 | global_type = 'wiggle';
15 |
16 | window.onresize = function(event) {
17 | $("#sticker").css('width', $("#base").width()+20);
18 | $("#sticker").css('height', $(".section").height());
19 |
20 | $("#sticker").sticky({
21 | topSpacing : 100,
22 | bottomSpacing: document.getElementById('footer').scrollHeight + 10,
23 | });
24 |
25 | $("svg").each(function() {
26 | /*var width = $(this).width();
27 |
28 | array = this.getAttribute("viewBox").match(/\d+/g);
29 | array[2] = width;
30 | this.setAttribute("viewBox",array.join(" "));*/
31 | });
32 | };
33 |
34 | var move_to = function(id) {
35 | $('html,body').animate({scrollTop: $(id).offset().top - 40 - $("h2").height()});
36 | };
37 |
38 | $(document).ready(function() {
39 | $("#fullpage").fullpage({
40 | autoScrolling: false,
41 | onLeave: function(index, nextIndex, direction){
42 | current_section = nextIndex;
43 | console.log(current_section);
44 |
45 | var chart = charts[current_section-3];
46 |
47 | if (global_type == 'zero' && chart.type == 'wiggle') {
48 | chart.zero_transition();
49 | } else if (global_type == 'wiggle' && chart.type == 'zero') {
50 | chart.wiggle_transition();
51 | }
52 |
53 | idx = chart.get_idx();
54 | $("#title").text(chart.get_layer()[idx].title);
55 |
56 | var node = chart.get_layer()[idx];
57 |
58 | if (node.type == 0)
59 | $("#naver-link").attr("href", "http://music.naver.com/music/bi/mi/basic.nhn?code="+node.code);
60 | else
61 | $("#naver-link").attr("href", "http://music.naver.com/music/bi/pi/basic.nhn?code="+node.code);
62 | $("#poster").attr('src', chart.get_layer()[idx].url);
63 | }
64 | });
65 |
66 | $("a.genre").click(function() {
67 | genre = $(this).attr('id');
68 |
69 | $("a.genre").removeClass('indigo');
70 | $(this).addClass('indigo');
71 |
72 | charts = [];
73 | $(".foxoffice").each(function() {
74 | $(this).html('
');
75 | });
76 |
77 | update_music(genre, global_type);
78 | });
79 |
80 | $("a.theme").click(function() {
81 | color = $(this).attr('id');
82 |
83 | if (color == "cyan") {
84 | color1 = "#006064",
85 | color2 = "#e0f7fa";
86 | } else if (color == "default") {
87 | color1 = "#045A8D",
88 | color2 = "#F1EEF6";
89 | } else if (color == "bg") {
90 | color1 = "#263238",
91 | color2 = "#eceff1";
92 | } else if (color == "teal") {
93 | color1 = "#004d40",
94 | color2 = "#e0f2f1";
95 | }
96 | for (var idx in charts) {
97 | chart = charts[idx];
98 | chart.update_color(color1, color2);
99 | }
100 | for (var idx in charts2) {
101 | chart = charts2[idx];
102 | chart.update_color(color1, color2);
103 | }
104 | });
105 |
106 | $("#sticker").sticky({
107 | topSpacing : 100,
108 | bottomSpacing: document.getElementById('footer').scrollHeight + 10,
109 | });
110 |
111 | $("#sticker").css('width', $("#base").width()+20);
112 | $("#sticker").css('height', $(".section").height());
113 |
114 | $('#graph-style input:radio').change( function(){
115 | var chart = charts[current_section-3];
116 |
117 | var type = $(this).attr('id');
118 |
119 | if (type == 'test1') {
120 | chart.wiggle_transition();
121 | global_type = 'wiggle';
122 | } else if (type == 'test2') {
123 | chart.zero_transition();
124 | global_type = 'zero';
125 | }
126 | });
127 | });
128 |
129 | var format = d3.time.format("%Y%m%d");
130 | var format2 = d3.time.format("%b");
131 |
132 | var charts = [];
133 | var charts2 = [];
134 |
135 | zero_stack = d3.layout.stack()
136 | .offset("zero")
137 | //.offset("silhouette")
138 | .values(function(d) { return d.values; })
139 | .x(function(d) { return d.x; })
140 | .y(function(d) { return d.y; });
141 |
142 | wiggle_stack = d3.layout.stack()
143 | .offset("wiggle")
144 | //.offset("silhouette")
145 | .values(function(d) { return d.values; })
146 | .x(function(d) { return d.x; })
147 | .y(function(d) { return d.y; });
148 |
149 | var Chart = function(year, class_name, genre, type) {
150 | var class_name = class_name;
151 | var year = year;
152 | var cidx;
153 |
154 | var height_base = $(window).height()*0.6;
155 |
156 | var margin = {top: 10, right: 10, bottom: 100, left: 20},
157 | margin2 = {top: height_base, right: 10, bottom: 20, left: 20},
158 | width = $("."+class_name).parent().width() - margin.left - margin.right - 3,
159 | height = height_base + 80 - margin.top - margin.bottom,
160 | height2 = height_base + 80 - margin2.top - margin2.bottom;
161 |
162 | var svg, context, focus;
163 |
164 | this.get_svg = function () {
165 | return svg;
166 | }
167 |
168 | var x = d3.scale.linear().range([0, width]),
169 | x2 = d3.scale.linear().range([0, width]),
170 | y = d3.scale.linear().range([height, 0]),
171 | y2 = d3.scale.linear().range([height2, 0]);
172 |
173 | var xAxis = d3.svg.axis().scale(x).orient("bottom")
174 | .ticks(3, function(d, i) {}),
175 | xAxis2 = d3.svg.axis().scale(x2).orient("bottom")
176 | .ticks(16, function(d, i) {});
177 |
178 | var brush = d3.svg.brush()
179 | .x(x2)
180 | .on("brush", brushed);
181 |
182 | function brushed() {
183 | x.domain(brush.empty() ? x2.domain() : brush.extent());
184 | focus.select(".x.axis").call(xAxis);
185 | focus.selectAll(".layer").attr("d", function(d) { return area(d.values); });
186 | };
187 |
188 | var color = d3.scale.linear()
189 | .range(["#3949ab", "#e8eaf6"]);
190 |
191 | var context_color = "#FC8D59";
192 | var context_idx = 0;
193 |
194 | this.get_idx = function() {
195 | return context_idx;
196 | }
197 |
198 | var area = d3.svg.area()
199 | //.interpolate("basis")
200 | .x(function(d) { return x(d.x); })
201 | .y0(function(d) { return y(d.y0); })
202 | .y1(function(d) { return y(d.y0 + d.y); });
203 |
204 | var area2 = d3.svg.area()
205 | .x(function(d) { return x2(d.x); })
206 | .y0(height2)
207 | .y1(function(d) { return y2(d.y); });
208 |
209 | /*var vertical_line = d3.select("#"+year).append("div")
210 | .attr("class", "remove")
211 | .style("position", "absolute")
212 | .style("z-index", "19")
213 | .style("width", "1px")
214 | .style("height", height+"px")
215 | .style("top", margin.top+"px")
216 | .style("bottom", margin.bottom+"px")
217 | .style("left", "0px")
218 | .style("background", "rgba(255,255,255,0.5)");*/
219 |
220 | var tooltip = d3.select("#"+year)
221 | .append("div")
222 | .attr("class", "remove")
223 | .style("position", "absolute")
224 | .style("z-index", "20")
225 | .style("visibility", "hidden")
226 | .style("top", "20px")
227 | .style("left", "75px");
228 |
229 | this.genre = genre;
230 |
231 | var get_year = function() {
232 | return year.match(/\d+/g)[0];
233 | }
234 |
235 | this.download = false;
236 |
237 | this.get_json = function() {
238 | this.download = false;
239 |
240 | year_number = year.match(/\d+/g)[0];
241 | d3.json("/carpedm20/vox/static/"+this.genre+"-"+year_number+".json", this.process);
242 | };
243 |
244 | this.change_genre = function(genre) {
245 | this.genre = genre;
246 | year_number = year.match(/\d+/g)[0];
247 | d3.json("/carpedm20/vox/static/"+this.genre+"-"+year_number+".json", this.process_update);
248 | };
249 |
250 | var layers = [];
251 | var layers0 = [];
252 |
253 | this.get_layer = function() {
254 | return layers;
255 | }
256 |
257 | this.type = type;
258 |
259 | this.zero_transition = function() {
260 | this.type = 'zero';
261 | zer = zero_stack(layers);
262 | y.domain([0, d3.max(zer, function(layer) { return d3.max(layer.values, function(d) { return d.y0 + d.y; }); })+1.5]);
263 | focus.selectAll(".layer")
264 | .data(function() {
265 | return zer;
266 | })
267 | .transition()
268 | .duration(2500)
269 | .attr("d", function(d) { return area(d.values); });
270 | }
271 |
272 | this.wiggle_transition = function() {
273 | this.type = 'wiggle';
274 | wig = wiggle_stack(layers);
275 | y.domain([0, d3.max(wig, function(layer) { return d3.max(layer.values, function(d) { return d.y0 + d.y; }); })]);
276 | focus.selectAll(".layer")
277 | .data(function() {
278 | return wig;
279 | })
280 | .transition()
281 | .duration(2500)
282 | .attr("d", function(d) { return area(d.values); });
283 | }
284 |
285 | this.transition = function() {
286 | focus.selectAll(".layer")
287 | .data(function() {
288 | d = layers0;
289 | layers0 = layers;
290 | return layers = d;
291 | })
292 | .transition()
293 | .duration(2500)
294 | .attr("d", function(d) { return area(d.values); });
295 | }
296 |
297 | this.update_color = function(color1, color2) {
298 | color = d3.scale.linear()
299 | .range([color1, color2]);
300 |
301 | color.domain([0, layers.length]);
302 |
303 | focus.selectAll("path")
304 | .style("fill", function(d) {
305 | if (d.idx == context_idx)
306 | return context_color;
307 | else
308 | return color(d.idx);
309 | });
310 | };
311 |
312 | var update_context = function(idx) {
313 | context_idx = idx;
314 |
315 | path = context.select("path");
316 |
317 | y2.domain([0, d3.max(layers[context_idx].values, function(value) {
318 | return value.y;
319 | })]);
320 |
321 | if (path[0][0] == null)
322 | path = context.append("path");
323 |
324 | path.datum(layers[idx])
325 | .attr("class", "area")
326 | .attr("d", function(d) { return area2(d.values); })
327 | .style("fill", function(d) { return context_color; });
328 |
329 | context.selectAll("g").remove();
330 |
331 | context.append("g")
332 | .attr("class", "x brush")
333 | .call(brush)
334 | .selectAll("rect")
335 | .attr("y", -6)
336 | .attr("height", height2 + 7);
337 | context.append("g")
338 | .attr("class", "x axis")
339 | .attr("transform", "translate(0," + height2 + ")")
340 | .call(xAxis2);
341 |
342 | focus.selectAll("path")
343 | .style("fill", function(d) {
344 | if (d.idx == idx)
345 | return context_color;
346 | else
347 | return color(d.idx);
348 | });
349 | };
350 |
351 | var clicked_idx = 0;
352 |
353 | this.process = function(error, data) {
354 | d3.select("#"+year).html('');
355 |
356 | var big_width = width + margin.left + margin.right,
357 | big_height = height + margin.top + margin.bottom;
358 |
359 | svg = d3.select("#"+year).append("svg")
360 | .attr("preserveAspectRatio", "xMinYMin")
361 | .attr("viewBox", "0 0 "+big_width+" "+big_height)
362 | .attr("width", "100%")
363 | //.attr("width", big_width)
364 | .attr("height", "80%");
365 |
366 | context = svg.append("g")
367 | .attr("class", "context")
368 | .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
369 |
370 | focus = svg.append("g")
371 | .attr("class", "focus")
372 | .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
373 |
374 | mindate = format.parse(get_year()+'0101');
375 | maxdate = format.parse(get_year()+'1231');
376 | skipdate = 7;
377 | y1 = data['y1'];
378 |
379 | xAxis.tickFormat(function(d) {
380 | date = new Date(mindate);
381 | date.setDate(mindate.getDate() + d*skipdate);
382 | return format2(date);
383 | });
384 |
385 | xAxis2.tickFormat(function(d) {
386 | date = new Date(mindate);
387 | date.setDate(mindate.getDate() + d*skipdate);
388 | return format2(date);
389 | });
390 |
391 | if (class_name == 'people')
392 | node_type = 1;
393 | else
394 | node_type= 0;
395 |
396 | for (var idx in y1) {
397 | for (var jdx in y1[idx]) {
398 | if (typeof layers[idx] == 'undefined') {
399 | if (class_name == 'people') {
400 | artist_code = data['musics'][idx][0].toString();
401 | } else {
402 | artist_code = data['musics'][idx][3].toString();
403 | }
404 |
405 | if (artist_code.length == 5)
406 | a = "0"+artist_code.slice(0,2);
407 | else if (artist_code.length == 4)
408 | a = "00"+artist_code.slice(0,1);
409 | else
410 | a = artist_code.slice(0,3);
411 |
412 | if (class_name == 'people') {
413 | layers[idx] = {title: data['musics'][idx][1],
414 | code : artist_code,
415 | type : node_type,
416 | url : "http://image.music.naver.net/artist/240/000/"+a+"/"+artist_code+".jpg",
417 | idx : idx,values:[]};
418 | layers0[idx] = {title: data['musics'][idx][1],
419 | code : artist_code,
420 | type : node_type,
421 | url : "http://image.music.naver.net/artist/240/000/"+a+"/"+artist_code+".jpg",
422 | idx : idx,values:[]};
423 | } else {
424 | layers[idx] = {title: data['musics'][idx][1],
425 | artist: data['musics'][idx][2],
426 | album_id: data['musics'][idx][3],
427 | artist_id: data['musics'][idx][4],
428 | url : "http://image.music.naver.net/album/204/000/"+a+"/"+data['musics'][idx][3]+".jpg",
429 | code : data['musics'][idx][0],
430 | type : node_type,
431 | idx : idx,values:[]};
432 | layers0[idx] = {title: data['musics'][idx][1],
433 | artist: data['musics'][idx][2],
434 | album_id: data['musics'][idx][3],
435 | artist_id: data['musics'][idx][4],
436 | url : "http://image.music.naver.net/album/204/000/"+a+"/"+data['musics'][idx][3]+".jpg",
437 | code : data['musics'][idx][0],
438 | type : node_type,
439 | idx : idx,values:[]};
440 | }
441 | }
442 | tmp = y1[idx][jdx];
443 | tmp = 1.0/tmp == Infinity ? 0 : 1.0/tmp;
444 | layers[idx].values.push({title:data['musics'][idx][1],
445 | x: Number(jdx),
446 | y: tmp});
447 | layers0[idx].values.push({title:data['musics'][idx][1],
448 | x: Number(jdx),
449 | y: 0});
450 | }
451 | }
452 |
453 | var n = layers.length;
454 |
455 | if (global_type == 'wiggle') {
456 | var stacked_layer = wiggle_stack(layers);
457 | y.domain([0, d3.max(stacked_layer, function(layer) { return d3.max(layer.values, function(d) { return d.y0 + d.y; }); })]);
458 | } else {
459 | var stacked_layer = zero_stack(layers);
460 | y.domain([0, d3.max(stacked_layer, function(layer) { return d3.max(layer.values, function(d) { return d.y0 + d.y; }); }) + 1.5]);
461 | }
462 |
463 | x.domain([0, d3.max(stacked_layer, function(layer) { return d3.max(layer.values, function(d) { return d.x; }); })]);
464 | x2.domain([0, d3.max(stacked_layer, function(layer) { return d3.max(layer.values, function(d) { return d.x; }); })]);
465 |
466 | color.domain([0, layers.length]);
467 |
468 | focus.selectAll(".layer")
469 | .data(stacked_layer)
470 | .enter().append("path")
471 | .attr("class", "layer")
472 | .attr("d", function(d) { return area(d.values); })
473 | .style("fill", function(d) {
474 | if (d.idx == context_idx)
475 | return context_color;
476 | else
477 | return color(d.idx);
478 | })
479 | .append("title")
480 | .text(function (d,i) { return d.title; });
481 |
482 | focus.append("g")
483 | .attr("class", "x axis")
484 | .attr("transform", "translate(0," + height + ")")
485 | .call(xAxis);
486 |
487 | update_context(clicked_idx);
488 |
489 | context.append("g")
490 | .attr("class", "x brush")
491 | .call(brush)
492 | .selectAll("rect")
493 | .attr("y", -6)
494 | .attr("height", height2 + 7);
495 |
496 | svg.selectAll(".layer")
497 | .attr("opacity", 1)
498 | .on("dblclick", function(d, i) {
499 | var win = window.open($("#naver-link").attr('href'), '_blank');
500 | win.focus();
501 | })
502 | .on("mouseover", function(d, i) {
503 | change_poster_specific(d.title, d.code, d.url, d.artist, d.artist_id, d.album_id);
504 | /*svg.selectAll(".layer")
505 | .attr("opacity", function(d, j) {
506 | return j != i ? 0.8 : 1;
507 | })
508 |
509 | mousex = d3.mouse(this);
510 | mousex = mousex[0] + 15;
511 | vertical_line.style("left", mousex + "px");*/
512 | })
513 | .on("mousemove", function(d, i){
514 | /*mousex = d3.mouse(this);
515 | mousex = mousex[0] + 15;
516 | vertical_line.style("left", mousex + "px" );
517 |
518 | current_x = Math.floor(x.invert(d3.mouse(this)[0]));
519 | var list = [];
520 |
521 | for (var idx in layers) {
522 | layer = layers[idx];
523 |
524 | list.push(layer.values[current_x]);
525 | }
526 |
527 | var sorted = list.sort(function (a,b) { return (b.y > a.y); });
528 |
529 | body = ''
530 |
531 | for (var idx in [0,1,2,3,4]) {
532 | body += sorted[idx].title[1] + '
';
533 | }
534 |
535 | html = "
" + body + "
";
536 | tooltip.html(html).style("visibility", "visible");*/
537 | })
538 | .on("click", function(d, i) {
539 | clicked_idx = d.idx;
540 |
541 | update_context(d.idx);
542 | change_poster();
543 |
544 | cidx = get_cidx();
545 |
546 | if (class_name == 'people')
547 | charts_to_find = charts2;
548 | else
549 | charts_to_find = charts;
550 |
551 | for (var idx in charts_to_find) {
552 | if (Number(idx) != cidx) {
553 | var chart = charts_to_find[idx];
554 |
555 | var title = d.title;
556 | var idx = title.indexOf("(");
557 |
558 | if (idx != -1)
559 | title = title.slice(0, title.indexOf("(")).trim()
560 | result = chart.find_code(d.code, title);
561 | }
562 | }
563 | })
564 | .on("mouseout", function(d, i) {
565 | svg.selectAll(".layer")
566 | .attr("opacity", "1");
567 | d3.select(this)
568 | .classed("hover", false)
569 | .attr("stroke-width", "0px");
570 |
571 | update_context(clicked_idx);
572 | change_poster();
573 |
574 | /*html = "
" + d.title + "
" + d.code + "
";
575 | tooltip.html(html).style("visibility", "hidden");*/
576 | });
577 | change_poster();
578 |
579 | this.download = true;
580 |
581 | progressJs().increase(18);
582 |
583 | var cidx = get_cidx() + 1;
584 |
585 | if (cidx == 7) {// && class_name == 'people') {
586 | progressJs().end();
587 | }
588 | if (cidx < charts.length) {
589 | if (class_name == 'people') {
590 | next_chart = charts2[cidx];
591 | } else
592 | next_chart = charts[cidx];
593 | next_chart.get_json();
594 | }
595 | };
596 |
597 | var get_cidx = function() {
598 | return cidx;
599 | }
600 |
601 | this.set_cidx = function(idx) {
602 | cidx = idx;
603 | }
604 |
605 | this.find_code = function(code, title) {
606 | for (var idx in layers) {
607 | layer = layers[idx];
608 |
609 | if (layer.code == code) {
610 | var year = get_year();
611 |
612 | if (class_name == 'people')
613 | var id = "#peo-" + year;
614 | else
615 | var id = "#mov-" + year;
616 |
617 | toast("
" + title + " found in " + year + "", 4000);
618 |
619 | clicked_idx = layer.idx;
620 | update_context(layer.idx);
621 | }
622 | }
623 | }
624 |
625 | var change_poster = function() {
626 | $("#title").text(layers[context_idx].title);
627 |
628 | var data = layers[context_idx];
629 | if (layers[context_idx].type == 0) {
630 | $("#naver-link").attr('href', "http://music.naver.com/album/index.nhn?albumId="+data.album_id+"&trackId="+data.code);
631 | $("#artist").attr('href', "http://music.naver.com/artist/home.nhn?artistId="+data.artist_id);
632 | $("#artist").text(data.artist);
633 | } else {
634 | $("#naver-link").attr('href', "http://music.naver.com/artist/home.nhn?artistId="+data.code);
635 | $("#artist").text('')
636 | $("#artist").attr('href', "");
637 | }
638 | $("#poster").attr('src', layers[context_idx].url);
639 | }
640 |
641 | var change_poster_specific = function(title, code, url, artist, artist_id, album_id) {
642 | $("#title").text(title);
643 | if (class_name != 'people') {
644 | $("#naver-link").attr('href', "http://music.naver.com/album/index.nhn?albumId="+album_id+"&trackId="+code);
645 | $("#artist").attr('href', "http://music.naver.com/artist/home.nhn?artistId="+artist_id);
646 | $("#artist").text(artist);
647 | } else {
648 | $("#naver-link").attr('href', "http://music.naver.com/artist/home.nhn?artistId="+code);
649 | $("#artist").text('')
650 | $("#artist").attr('href', "");
651 | }
652 | $("#poster").attr('src', url);
653 | }
654 | };
655 |
656 | var update_music = function(genre, type) {
657 |
658 | $(".foxoffice").each(function() {
659 | year = $(this).attr('id');
660 |
661 | chart = new Chart(year, 'foxoffice', genre, type);
662 | chart.set_cidx(charts.length);
663 | charts.push(chart);
664 | });
665 |
666 | charts[0].get_json();
667 | }
668 |
669 | var update_people = function(type) {
670 | $(".people").each(function() {
671 | year = $(this).attr('id');
672 |
673 | chart = new Chart(year, 'people', 'artist', type);
674 | chart.set_cidx(charts2.length);
675 | charts2.push(chart);
676 | });
677 |
678 | charts2[0].get_json();
679 | }
680 |
681 | update_music('total', 'wiggle');
682 | //update_people('people');
683 |
--------------------------------------------------------------------------------
/static/music_color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/music_color.png
--------------------------------------------------------------------------------
/static/music_color_ko.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/music_color_ko.png
--------------------------------------------------------------------------------
/static/music_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/music_logo.png
--------------------------------------------------------------------------------
/static/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/screenshot.png
--------------------------------------------------------------------------------
/static/script.js:
--------------------------------------------------------------------------------
1 | window.mobilecheck = function() {
2 | var check = false;
3 | (function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
4 | return check;
5 | }
6 |
7 | if (window.mobilecheck()) {
8 | alert("Voxoffice는 모바일 브라우저를 지원하지 않습니다");
9 | }
10 |
11 | progressJs().start();
12 |
13 | current_section = 3;
14 | global_type = 'wiggle';
15 |
16 | window.onresize = function(event) {
17 | $("#sticker").css('width', $("#base").width()+20);
18 | $("#sticker").css('height', $(".section").height());
19 |
20 | $("#sticker").sticky({
21 | topSpacing : 100,
22 | bottomSpacing: document.getElementById('footer').scrollHeight + 10,
23 | });
24 |
25 | $("svg").each(function() {
26 | /*var width = $(this).width();
27 |
28 | array = this.getAttribute("viewBox").match(/\d+/g);
29 | array[2] = width;
30 | this.setAttribute("viewBox",array.join(" "));*/
31 | });
32 | };
33 |
34 | var move_to = function(id) {
35 | $('html,body').animate({scrollTop: $(id).offset().top - 40 - $("h2").height()});
36 | };
37 |
38 | $(document).ready(function() {
39 | $("#fullpage").fullpage({
40 | autoScrolling: false,
41 | onLeave: function(index, nextIndex, direction){
42 | current_section = nextIndex;
43 | console.log(current_section);
44 |
45 | if (current_section % 2 == 1) {
46 | var chart = charts2[Math.floor(current_section/2)-2];
47 | } else {
48 | var chart = charts[current_section/2-2];
49 | }
50 |
51 | if (global_type == 'zero' && chart.type == 'wiggle') {
52 | chart.zero_transition();
53 | } else if (global_type == 'wiggle' && chart.type == 'zero') {
54 | chart.wiggle_transition();
55 | }
56 |
57 | idx = chart.get_idx();
58 | $("#title").text(chart.get_layer()[idx].title);
59 |
60 | var node = chart.get_layer()[idx];
61 |
62 | if (node.type == 0)
63 | $("#naver-link").attr("href", "http://movie.naver.com/movie/bi/mi/basic.nhn?code="+node.code);
64 | else
65 | $("#naver-link").attr("href", "http://movie.naver.com/movie/bi/pi/basic.nhn?code="+node.code);
66 | $("#poster").attr('src', chart.get_layer()[idx].url);
67 | }
68 | });
69 |
70 | $("a.genre").click(function() {
71 | genre = $(this).attr('id');
72 |
73 | $("a.genre").removeClass('teal');
74 | $(this).addClass('teal');
75 |
76 | charts = [];
77 | $(".foxoffice").each(function() {
78 | $(this).html('
');
79 | });
80 |
81 | update_movie(genre, global_type);
82 | });
83 |
84 | $("a.theme").click(function() {
85 | color = $(this).attr('id');
86 |
87 | if (color == "cyan") {
88 | color1 = "#006064",
89 | color2 = "#e0f7fa";
90 | } else if (color == "default") {
91 | color1 = "#045A8D",
92 | color2 = "#F1EEF6";
93 | } else if (color == "bg") {
94 | color1 = "#263238",
95 | color2 = "#eceff1";
96 | } else if (color == "teal") {
97 | color1 = "#004d40",
98 | color2 = "#e0f2f1";
99 | }
100 | for (var idx in charts) {
101 | chart = charts[idx];
102 | chart.update_color(color1, color2);
103 | }
104 | for (var idx in charts2) {
105 | chart = charts2[idx];
106 | chart.update_color(color1, color2);
107 | }
108 | });
109 |
110 | $("#sticker").sticky({
111 | topSpacing : 100,
112 | bottomSpacing: document.getElementById('footer').scrollHeight + 10,
113 | });
114 |
115 | $("#sticker").css('width', $("#base").width()+20);
116 | $("#sticker").css('height', $(".section").height());
117 |
118 | $('#graph-style input:radio').change( function(){
119 | if (current_section % 2 == 1) {
120 | var chart = charts2[Math.floor(current_section/2)-2];
121 | } else {
122 | var chart = charts[current_section/2-2];
123 | }
124 |
125 | var type = $(this).attr('id');
126 |
127 | if (type == 'test1') {
128 | chart.wiggle_transition();
129 | global_type = 'wiggle';
130 | } else if (type == 'test2') {
131 | chart.zero_transition();
132 | global_type = 'zero';
133 | }
134 | });
135 | });
136 |
137 | var format = d3.time.format("%Y%m%d");
138 | var format2 = d3.time.format("%b");
139 |
140 | var charts = [];
141 | var charts2 = [];
142 |
143 | zero_stack = d3.layout.stack()
144 | .offset("zero")
145 | //.offset("silhouette")
146 | .values(function(d) { return d.values; })
147 | .x(function(d) { return d.x; })
148 | .y(function(d) { return d.y; });
149 |
150 | wiggle_stack = d3.layout.stack()
151 | .offset("wiggle")
152 | //.offset("silhouette")
153 | .values(function(d) { return d.values; })
154 | .x(function(d) { return d.x; })
155 | .y(function(d) { return d.y; });
156 |
157 | var Chart = function(year, class_name, genre, type) {
158 | var class_name = class_name;
159 | var year = year;
160 | var cidx;
161 |
162 | var height_base = $(window).height()*0.6;
163 |
164 | var margin = {top: 10, right: 10, bottom: 100, left: 20},
165 | margin2 = {top: height_base, right: 10, bottom: 20, left: 20},
166 | width = $("."+class_name).parent().width() - margin.left - margin.right - 3,
167 | height = height_base + 80 - margin.top - margin.bottom,
168 | height2 = height_base + 80 - margin2.top - margin2.bottom;
169 |
170 | var svg, context, focus;
171 |
172 | var x = d3.scale.linear().range([0, width]),
173 | x2 = d3.scale.linear().range([0, width]),
174 | y = d3.scale.linear().range([height, 0]),
175 | y2 = d3.scale.linear().range([height2, 0]);
176 |
177 | var xAxis = d3.svg.axis().scale(x).orient("bottom")
178 | .ticks(3, function(d, i) {}),
179 | xAxis2 = d3.svg.axis().scale(x2).orient("bottom")
180 | .ticks(8, function(d, i) {});
181 |
182 | var brush = d3.svg.brush()
183 | .x(x2)
184 | .on("brush", brushed);
185 |
186 | function brushed() {
187 | x.domain(brush.empty() ? x2.domain() : brush.extent());
188 | focus.select(".x.axis").call(xAxis);
189 | focus.selectAll(".layer").attr("d", function(d) { return area(d.values); });
190 | };
191 |
192 | var color = d3.scale.linear()
193 | .range(["#045A8D", "#F1EEF6"]);
194 |
195 | var context_color = "#FC8D59";
196 | var context_idx = 0;
197 |
198 | this.get_idx = function() {
199 | return context_idx;
200 | }
201 |
202 | var area = d3.svg.area()
203 | //.interpolate("basis")
204 | .x(function(d) { return x(d.x); })
205 | .y0(function(d) { return y(d.y0); })
206 | .y1(function(d) { return y(d.y0 + d.y); });
207 |
208 | var area2 = d3.svg.area()
209 | .x(function(d) { return x2(d.x); })
210 | .y0(height2)
211 | .y1(function(d) { return y2(d.y); });
212 |
213 | /*var vertical_line = d3.select("#"+year).append("div")
214 | .attr("class", "remove")
215 | .style("position", "absolute")
216 | .style("z-index", "19")
217 | .style("width", "1px")
218 | .style("height", height+"px")
219 | .style("top", margin.top+"px")
220 | .style("bottom", margin.bottom+"px")
221 | .style("left", "0px")
222 | .style("background", "rgba(255,255,255,0.5)");*/
223 |
224 | var tooltip = d3.select("#"+year)
225 | .append("div")
226 | .attr("class", "remove")
227 | .style("position", "absolute")
228 | .style("z-index", "20")
229 | .style("visibility", "hidden")
230 | .style("top", "20px")
231 | .style("left", "75px");
232 |
233 | this.genre = genre;
234 |
235 | var get_year = function() {
236 | return year.match(/\d+/g)[0];
237 | }
238 |
239 | this.download = false;
240 |
241 | this.get_json = function() {
242 | this.download = false;
243 |
244 | year_number = year.match(/\d+/g)[0];
245 | d3.json("./static/"+this.genre+"-"+year_number+".json", this.process);
246 | };
247 |
248 | this.change_genre = function(genre) {
249 | this.genre = genre;
250 | year_number = year.match(/\d+/g)[0];
251 | d3.json("./static/"+this.genre+"-"+year_number+".json", this.process_update);
252 | };
253 |
254 | var layers = [];
255 | var layers0 = [];
256 |
257 | this.get_layer = function() {
258 | return layers;
259 | }
260 |
261 | this.type = type;
262 |
263 | this.zero_transition = function() {
264 | this.type = 'zero';
265 | zer = zero_stack(layers);
266 | y.domain([0, d3.max(zer, function(layer) { return d3.max(layer.values, function(d) { return d.y0 + d.y; }); })+1.5]);
267 | focus.selectAll(".layer")
268 | .data(function() {
269 | return zer;
270 | })
271 | .transition()
272 | .duration(2500)
273 | .attr("d", function(d) { return area(d.values); });
274 | }
275 |
276 | this.wiggle_transition = function() {
277 | this.type = 'wiggle';
278 | wig = wiggle_stack(layers);
279 | y.domain([0, d3.max(wig, function(layer) { return d3.max(layer.values, function(d) { return d.y0 + d.y; }); })]);
280 | focus.selectAll(".layer")
281 | .data(function() {
282 | return wig;
283 | })
284 | .transition()
285 | .duration(2500)
286 | .attr("d", function(d) { return area(d.values); });
287 | }
288 |
289 | this.transition = function() {
290 | focus.selectAll(".layer")
291 | .data(function() {
292 | d = layers0;
293 | layers0 = layers;
294 | return layers = d;
295 | })
296 | .transition()
297 | .duration(2500)
298 | .attr("d", function(d) { return area(d.values); });
299 | }
300 |
301 | this.update_color = function(color1, color2) {
302 | color = d3.scale.linear()
303 | .range([color1, color2]);
304 |
305 | color.domain([0, layers.length]);
306 |
307 | focus.selectAll("path")
308 | .style("fill", function(d) {
309 | if (d.idx == context_idx)
310 | return context_color;
311 | else
312 | return color(d.idx);
313 | });
314 | };
315 |
316 | var update_context = function(idx) {
317 | context_idx = idx;
318 |
319 | path = context.select("path");
320 |
321 | y2.domain([0, d3.max(layers[context_idx].values, function(value) {
322 | return value.y;
323 | })]);
324 |
325 | if (path[0][0] == null)
326 | path = context.append("path");
327 |
328 | path.datum(layers[idx])
329 | .attr("class", "area")
330 | .attr("d", function(d) { return area2(d.values); })
331 | .style("fill", function(d) { return context_color; });
332 |
333 | context.selectAll("g").remove();
334 |
335 | context.append("g")
336 | .attr("class", "x brush")
337 | .call(brush)
338 | .selectAll("rect")
339 | .attr("y", -6)
340 | .attr("height", height2 + 7);
341 | context.append("g")
342 | .attr("class", "x axis")
343 | .attr("transform", "translate(0," + height2 + ")")
344 | .call(xAxis2);
345 |
346 | focus.selectAll("path")
347 | .style("fill", function(d) {
348 | if (d.idx == idx)
349 | return context_color;
350 | else
351 | return color(d.idx);
352 | });
353 | };
354 |
355 | var clicked_idx = 0;
356 |
357 | this.process = function(error, data) {
358 | d3.select("#"+year).html('');
359 |
360 | var big_width = width + margin.left + margin.right,
361 | big_height = height + margin.top + margin.bottom;
362 |
363 | svg = d3.select("#"+year).append("svg")
364 | .attr("preserveAspectRatio", "xMinYMin")
365 | .attr("viewBox", "0 0 "+big_width+" "+big_height)
366 | .attr("width", "100%")
367 | //.attr("width", big_width)
368 | .attr("height", "80%");
369 |
370 | context = svg.append("g")
371 | .attr("class", "context")
372 | .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
373 |
374 | focus = svg.append("g")
375 | .attr("class", "focus")
376 | .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
377 |
378 | mindate = format.parse(data['mindate']);
379 | maxdate = format.parse(data['maxdate']);
380 | skipdate = 5;
381 | y1 = data['y1'];
382 |
383 | xAxis.tickFormat(function(d) {
384 | date = new Date(mindate);
385 | date.setDate(mindate.getDate() + d*skipdate);
386 | return format2(date);
387 | });
388 |
389 | xAxis2.tickFormat(function(d) {
390 | date = new Date(mindate);
391 | date.setDate(mindate.getDate() + d*skipdate);
392 | return format2(date);
393 | });
394 |
395 | if (class_name == 'people')
396 | node_type = 1;
397 | else
398 | node_type= 0;
399 |
400 | for (var idx in y1) {
401 | for (var jdx in y1[idx]) {
402 | if (typeof layers[idx] == 'undefined') {
403 | a = data['movies'][idx][1];
404 | layers[idx] = {title : data['movies'][idx][2],
405 | url : data['movies'][idx][1][0],
406 | code : data['movies'][idx][0],
407 | type : node_type,
408 | idx : idx,values:[]};
409 | layers0[idx] = {title : data['movies'][idx][1],
410 | code : data['movies'][idx][0],
411 | type : node_type,
412 | idx : idx,values:[]};
413 | }
414 | tmp = y1[idx][jdx];
415 | tmp = 1.0/tmp == Infinity ? 0 : 1.0/tmp;
416 | layers[idx].values.push({title:data['movies'][idx][1],
417 | x: Number(jdx),
418 | y: tmp});
419 | layers0[idx].values.push({title:data['movies'][idx][1],
420 | x: Number(jdx),
421 | y: 0});
422 | }
423 | }
424 |
425 | var n = layers.length;
426 |
427 | if (global_type == 'wiggle') {
428 | var stacked_layer = wiggle_stack(layers);
429 | y.domain([0, d3.max(stacked_layer, function(layer) { return d3.max(layer.values, function(d) { return d.y0 + d.y; }); })]);
430 | } else {
431 | var stacked_layer = zero_stack(layers);
432 | y.domain([0, d3.max(stacked_layer, function(layer) { return d3.max(layer.values, function(d) { return d.y0 + d.y; }); }) + 1.5]);
433 | }
434 |
435 | x.domain([0, d3.max(stacked_layer, function(layer) { return d3.max(layer.values, function(d) { return d.x; }); })]);
436 | x2.domain([0, d3.max(stacked_layer, function(layer) { return d3.max(layer.values, function(d) { return d.x; }); })]);
437 | y.domain([0, d3.max(stacked_layer, function(layer) { return d3.max(layer.values, function(d) { return d.y0 + d.y; }); })]);
438 |
439 | color.domain([0, layers.length]);
440 |
441 | focus.selectAll(".layer")
442 | .data(stacked_layer)
443 | .enter().append("path")
444 | .attr("class", "layer")
445 | .attr("d", function(d) { return area(d.values); })
446 | .style("fill", function(d) {
447 | if (d.idx == context_idx)
448 | return context_color;
449 | else
450 | return color(d.idx);
451 | })
452 | .append("title")
453 | .text(function (d,i) { return d.title; });
454 |
455 | focus.append("g")
456 | .attr("class", "x axis")
457 | .attr("transform", "translate(0," + height + ")")
458 | .call(xAxis);
459 |
460 | update_context(clicked_idx);
461 |
462 | context.append("g")
463 | .attr("class", "x brush")
464 | .call(brush)
465 | .selectAll("rect")
466 | .attr("y", -6)
467 | .attr("height", height2 + 7);
468 |
469 | svg.selectAll(".layer")
470 | .attr("opacity", 1)
471 | .on("dblclick", function(d, i) {
472 | var win = window.open($("#naver-link").attr('href'), '_blank');
473 | win.focus();
474 | })
475 | .on("mouseover", function(d, i) {
476 | change_poster_specific(d.title, d.code, d.url);
477 | /*svg.selectAll(".layer")
478 | .attr("opacity", function(d, j) {
479 | return j != i ? 0.8 : 1;
480 | })
481 |
482 | mousex = d3.mouse(this);
483 | mousex = mousex[0] + 15;
484 | vertical_line.style("left", mousex + "px");*/
485 | })
486 | .on("mousemove", function(d, i){
487 | /*mousex = d3.mouse(this);
488 | mousex = mousex[0] + 15;
489 | vertical_line.style("left", mousex + "px" );
490 |
491 | current_x = Math.floor(x.invert(d3.mouse(this)[0]));
492 | var list = [];
493 |
494 | for (var idx in layers) {
495 | layer = layers[idx];
496 |
497 | list.push(layer.values[current_x]);
498 | }
499 |
500 | var sorted = list.sort(function (a,b) { return (b.y > a.y); });
501 |
502 | body = ''
503 |
504 | for (var idx in [0,1,2,3,4]) {
505 | body += sorted[idx].title[1] + '
';
506 | }
507 |
508 | html = "
" + body + "
";
509 | tooltip.html(html).style("visibility", "visible");*/
510 | })
511 | .on("click", function(d, i) {
512 | clicked_idx = d.idx;
513 |
514 | update_context(d.idx);
515 | change_poster();
516 |
517 | cidx = get_cidx();
518 |
519 | if (class_name == 'people')
520 | charts_to_find = charts2;
521 | else
522 | charts_to_find = charts;
523 |
524 | for (var idx in charts_to_find) {
525 | if (Number(idx) != cidx) {
526 | var chart = charts_to_find[idx];
527 |
528 | var title = d.title;
529 | var idx = title.indexOf("(");
530 |
531 | if (idx != -1)
532 | title = title.slice(0, title.indexOf("(")).trim()
533 | result = chart.find_code(d.code, title);
534 | }
535 | }
536 | })
537 | .on("mouseout", function(d, i) {
538 | svg.selectAll(".layer")
539 | .attr("opacity", "1");
540 | d3.select(this)
541 | .classed("hover", false)
542 | .attr("stroke-width", "0px");
543 |
544 | update_context(clicked_idx);
545 | change_poster();
546 |
547 | /*html = "
" + d.title + "
" + d.code + "
";
548 | tooltip.html(html).style("visibility", "hidden");*/
549 | });
550 | change_poster();
551 |
552 | this.download = true;
553 |
554 | progressJs().increase(6.25);
555 |
556 | var cidx = get_cidx() + 1;
557 |
558 | if (cidx == 8 && class_name == 'people') {
559 | progressJs().end();
560 | }
561 | if (cidx < charts.length) {
562 | if (class_name == 'people') {
563 | next_chart = charts2[cidx];
564 | } else
565 | next_chart = charts[cidx];
566 | next_chart.get_json();
567 | }
568 | };
569 |
570 | var get_cidx = function() {
571 | return cidx;
572 | }
573 |
574 | this.set_cidx = function(idx) {
575 | cidx = idx;
576 | }
577 |
578 | this.find_code = function(code, title) {
579 | for (var idx in layers) {
580 | layer = layers[idx];
581 |
582 | if (layer.code == code) {
583 | var year = get_year();
584 |
585 | if (class_name == 'people')
586 | var id = "#peo-" + year;
587 | else
588 | var id = "#mov-" + year;
589 |
590 | toast("
" + title + " found in " + year + "", 4000);
591 |
592 | clicked_idx = layer.idx;
593 | update_context(layer.idx);
594 | }
595 | }
596 | }
597 |
598 | var change_poster = function() {
599 | $("#title").text(layers[context_idx].title);
600 | if (layers[context_idx].type == 0)
601 | $("#naver-link").attr('href', "http://movie.naver.com/movie/bi/mi/basic.nhn?code="+layers[context_idx].code);
602 | else
603 | $("#naver-link").attr('href', "http://movie.naver.com/movie/bi/pi/basic.nhn?code="+layers[context_idx].code);
604 | $("#poster").attr('src', layers[context_idx].url);
605 | }
606 |
607 | var change_poster_specific = function(title, code, url) {
608 | $("#title").text(title);
609 | if (class_name == 'people')
610 | $("#naver-link").attr('href', "http://movie.naver.com/movie/bi/pi/basic.nhn?code="+code);
611 | else
612 | $("#naver-link").attr('href', "http://movie.naver.com/movie/bi/mi/basic.nhn?code="+code);
613 | $("#poster").attr('src', url);
614 | }
615 | };
616 |
617 | var update_movie = function(genre, type) {
618 |
619 | $(".foxoffice").each(function() {
620 | year = $(this).attr('id');
621 |
622 | chart = new Chart(year, 'foxoffice', genre, type);
623 | chart.set_cidx(charts.length);
624 | charts.push(chart);
625 | });
626 |
627 | charts[0].get_json();
628 | }
629 |
630 | var update_people = function(type) {
631 | $(".people").each(function() {
632 | year = $(this).attr('id');
633 |
634 | chart = new Chart(year, 'people', 'people', type);
635 | chart.set_cidx(charts2.length);
636 | charts2.push(chart);
637 | });
638 |
639 | charts2[0].get_json();
640 | }
641 |
642 | update_movie('all', 'wiggle');
643 | update_people('wiggle');
644 |
--------------------------------------------------------------------------------
/static/style.css:
--------------------------------------------------------------------------------
1 | @import url(http://fonts.googleapis.com/earlyaccess/nanumgothic.css);
2 |
3 | .progressjs-inner {
4 | background-color: #ff9800 !important;
5 | height: 6px !important;
6 | }
7 |
8 | body {
9 | font-family: 'Ubuntu', sans-serif;
10 | min-width: 970px;
11 | font-family: sans-serif;
12 | -ms-text-size-adjust: 100%;
13 | -webkit-text-size-adjust: 100%;
14 | }
15 |
16 | p, a, h1, span, label, text {
17 | font-family: 'Ubuntu', sans-serif;
18 | }
19 |
20 | .music-genre-btn {
21 | background-color: #607d8b;
22 | }
23 |
24 | .toast {
25 | font-size: 0.9em;
26 | background: rgba(20,24,28,.95);
27 | }
28 |
29 | .ko {
30 | font-family: 'Nanum Barun Gothic', 'Nanum Gothic', serif !important;
31 | }
32 |
33 | .ko-title {
34 | font-size: 1.3em !important;
35 | }
36 |
37 | .foxoffice, .people {
38 | width: 100%;
39 | height: 100%;
40 | position: relative;
41 | }
42 |
43 | .grey li a {
44 | color: white;
45 | }
46 |
47 | .logo-text {
48 | font-size: 7rem;
49 | }
50 |
51 | nav .brand-logo {
52 | position: absolute;
53 | color: #fff;
54 | display: inline-block;
55 | font-size: 1.5rem;
56 | padding: 0;
57 | }
58 |
59 | ul.menu li a {
60 | font-size: 1.2em;
61 | }
62 |
63 |
64 | .axis {
65 | shape-rendering: crispEdges;
66 | }
67 |
68 | .x.axis line {
69 | stroke: white;
70 | }
71 |
72 | .x.axis .minor {
73 | stroke-opacity: .5;
74 | }
75 |
76 | .x.axis path {
77 | display: none;
78 | }
79 |
80 | .y.axis line, .y.axis path {
81 | fill: none;
82 | stroke: white;
83 | }
84 |
85 | .brush .extent {
86 | stroke: #fff;
87 | fill-opacity: .125;
88 | shape-rendering: crispEdges;
89 | }
90 |
91 | .yir-generic {
92 | position: relative;
93 | background: #1b2128;
94 | width: 100%;
95 | height: 100%;
96 | color: #9ab;
97 | }
98 |
99 | .nav-bar {
100 | background: rgba(20,24,28,.95);
101 | position: fixed;
102 | z-index: 1;
103 | top: 0;
104 | left: 0;
105 | width: 100%;
106 | padding-right: 50px;
107 | padding-left: 50px;
108 | }
109 |
110 | .yir-generic-music {
111 | position: relative;
112 | background: #ecf0f1;
113 | width: 100%;
114 | height: 100%;
115 | color: #9ab;
116 | }
117 |
118 | .nav-bar-music {
119 | background: rgba(65,91,118,.95);
120 | position: fixed;
121 | z-index: 1;
122 | top: 0;
123 | left: 0;
124 | width: 100%;
125 | padding-right: 50px;
126 | padding-left: 50px;
127 | }
128 |
129 | .text p {
130 | font-family: Vollkorn, Georgia,serif;
131 | font-size: 24px;
132 | font-weight: 400;
133 | line-height: 1.4;
134 | }
135 |
136 | .footnote {
137 | font-family: Ubuntu,sans-serif;
138 | font-size: 18px;
139 | font-weight: 400;
140 | margin: 0 100px;
141 | }
142 |
143 | .footnote a {
144 | color: #def;
145 | }
146 |
147 | label {
148 | font-size: 1.0rem;
149 | }
150 |
151 | .shadow {
152 | width: 25px;
153 | height: 25px;
154 | margin: 20px auto;
155 | }
156 |
157 | a.genre {
158 | height: 32px;
159 | font-size: 0.5rem;
160 | padding-left: 12px;
161 | padding-right: 12px;
162 | margin-right: 2px;
163 | }
164 |
165 | .materialboxed {
166 | width: 100%;
167 | }
168 |
169 | div.about-me {
170 | padding-left: 10px;
171 | }
172 |
173 | div.contact {
174 | padding-left: 30px;
175 | }
176 |
177 | div.footer-copyright {
178 | text-align: right;
179 | }
180 |
181 | div.insight-container {
182 | width: 90%;
183 | }
184 |
185 | div.info-card {
186 | min-height: 250px;
187 | }
188 |
189 | .ubuntu {
190 | font-family: Ubuntu,sans-serif;
191 | }
192 |
193 | .strip-overlay {
194 | background: rgba(68,85,102,.4);
195 | position: absolute;
196 | top: 0;
197 | left: 0;
198 | width: 100%;
199 | height: 100%;
200 | }
201 |
202 | .year-poster {
203 | position: absolute;
204 | top: 0;
205 | left: 0;
206 | width: 100%;
207 | height: 100%;
208 | margin-bottom: 0px;
209 | background-size: cover;
210 | background-position: center;
211 | background-repeat: no-repeat;
212 | }
213 |
214 | .year-poster-img {
215 | height:100%;
216 | }
217 |
218 | .year-poster-content {
219 | width: 90%;
220 | padding-top: 10%;
221 | box-sizing: border-box;
222 | height: 100%;
223 | font-weight: 400;
224 | position: relative;
225 | }
226 |
227 | .year-poster-text {
228 | width: 60%;
229 | float: right;
230 | text-align: right;
231 | }
232 |
233 | .year-poster-text h2 a {
234 | color: #fff;
235 | font-weight: 400;
236 | font-size: 95px;
237 | line-height: 1em;
238 | }
239 |
240 | .year-poster-content h1 span {
241 | font-weight: 400;
242 | font-size: 18px;
243 | line-height: 1;
244 | display: inline-block;
245 | background-color: rgba(0,0,0,.3);
246 | border: 1px solid rgba(255,255,255,.6);
247 | color: #fff;
248 | padding: 5px 8px 6px;
249 | text-transform: uppercase;
250 | letter-spacing: .1em;
251 | white-space: nowrap;
252 | -webkit-box-shadow: 1px 1px 2px rgba(0,0,0,.25);
253 | -moz-box-shadow: 1px 1px 2px rgba(0,0,0,.25);
254 | box-shadow: 1px 1px 2px rgba(0,0,0,.25);
255 | -webkit-border-radius: 2px;
256 | -moz-border-radius: 2px;
257 | border-radius: 2px;
258 | }
259 |
260 | .card a {
261 | margin-right: 0px;
262 | }
263 |
264 | .img-block-strip {
265 | width: 100%;
266 | height: 300px;
267 | position: absolute;
268 | bottom: 0;
269 | left: 0;
270 | overflow: hidden;
271 | }
272 |
273 | .loading {
274 | margin-top: 240px;
275 | margin-bottom: 240px;
276 | }
277 |
278 | .no-bottom {
279 | margin-bottom: 0px;
280 | }
281 |
282 |
283 | .progressjs-inner {
284 | width: 0;
285 | }
286 | .progressjs-progress {
287 | z-index: 9999999;
288 | }
289 |
290 | /* blue theme, like iOS 7 progress bar */
291 | .progressjs-theme-blue .progressjs-inner {
292 | height: 2px;
293 | -webkit-transition: all 0.3s ease-out;
294 | -moz-transition: all 0.3s ease-out;
295 | -o-transition: all 0.3s ease-out;
296 | transition: all 0.3s ease-out;
297 | background-color: #3498db;
298 | }
299 | .progressjs-theme-blue.progressjs-end {
300 | -webkit-transition: opacity 0.2s ease-out;
301 | -moz-transition: opacity 0.2s ease-out;
302 | -o-transition: opacity 0.2s ease-out;
303 | transition: opacity 0.2s ease-out;
304 | opacity: 0;
305 | }
306 | .progressjs-theme-blue .progressjs-percent {
307 | display: none;
308 | }
309 |
310 | /* blue theme with overlay layer, no percent bar */
311 | .progressjs-theme-blueOverlay {
312 | background-color: white;
313 | -webkit-transition: all 0.2s ease-out;
314 | -moz-transition: all 0.2s ease-out;
315 | -o-transition: all 0.2s ease-out;
316 | transition: all 0.2s ease-out;
317 | }
318 | .progressjs-theme-blueOverlay .progressjs-inner {
319 | height: 100%;
320 | -webkit-transition: all 0.3s ease-out;
321 | -moz-transition: all 0.3s ease-out;
322 | -o-transition: all 0.3s ease-out;
323 | transition: all 0.3s ease-out;
324 | background-color: #3498db;
325 | }
326 | .progressjs-theme-blueOverlay.progressjs-end {
327 | opacity: 0 !important;
328 | }
329 | .progressjs-theme-blueOverlay .progressjs-percent {
330 | display: none;
331 | }
332 |
333 | /* blue theme with overlay layer, no percent bar */
334 | .progressjs-theme-blueOverlay {
335 | background-color: white;
336 | -webkit-transition: all 0.2s ease-out;
337 | -moz-transition: all 0.2s ease-out;
338 | -o-transition: all 0.2s ease-out;
339 | transition: all 0.2s ease-out;
340 | }
341 | .progressjs-theme-blueOverlay .progressjs-inner {
342 | height: 100%;
343 | -webkit-transition: all 0.3s ease-out;
344 | -moz-transition: all 0.3s ease-out;
345 | -o-transition: all 0.3s ease-out;
346 | transition: all 0.3s ease-out;
347 | background-color: #3498db;
348 | }
349 | .progressjs-theme-blueOverlay.progressjs-end {
350 | opacity: 0 !important;
351 | }
352 | .progressjs-theme-blueOverlay .progressjs-percent {
353 | display: none;
354 | }
355 |
356 | /* Blue theme with border radius and overlay layer */
357 | .progressjs-theme-blueOverlayRadius {
358 | background-color: white;
359 | -webkit-transition: all 0.2s ease-out;
360 | -moz-transition: all 0.2s ease-out;
361 | -o-transition: all 0.2s ease-out;
362 | transition: all 0.2s ease-out;
363 | border-radius: 5px;
364 | }
365 | .progressjs-theme-blueOverlayRadius .progressjs-inner {
366 | height: 100%;
367 | -webkit-transition: all 0.3s ease-out;
368 | -moz-transition: all 0.3s ease-out;
369 | -o-transition: all 0.3s ease-out;
370 | transition: all 0.3s ease-out;
371 | background-color: #3498db;
372 | border-radius: 5px;
373 | }
374 | .progressjs-theme-blueOverlayRadius.progressjs-end {
375 | opacity: 0 !important;
376 | }
377 | .progressjs-theme-blueOverlayRadius .progressjs-percent {
378 | display: none;
379 | }
380 |
381 | /* Blue theme with border radius and overlay layer */
382 | .progressjs-theme-blueOverlayRadiusHalfOpacity {
383 | background-color: white;
384 | opacity: 0.5;
385 | -webkit-transition: all 0.2s ease-out;
386 | -moz-transition: all 0.2s ease-out;
387 | -o-transition: all 0.2s ease-out;
388 | transition: all 0.2s ease-out;
389 | border-radius: 5px;
390 | }
391 | .progressjs-theme-blueOverlayRadiusHalfOpacity .progressjs-inner {
392 | height: 100%;
393 | -webkit-transition: all 0.3s ease-out;
394 | -moz-transition: all 0.3s ease-out;
395 | -o-transition: all 0.3s ease-out;
396 | transition: all 0.3s ease-out;
397 | background-color: #3498db;
398 | border-radius: 5px;
399 | }
400 | .progressjs-theme-blueOverlayRadiusHalfOpacity.progressjs-end {
401 | opacity: 0 !important;
402 | }
403 | .progressjs-theme-blueOverlayRadiusHalfOpacity .progressjs-percent {
404 | display: none;
405 | }
406 |
407 | /* Blue theme with border radius, overlay layer and percent bar */
408 | .progressjs-theme-blueOverlayRadiusWithPercentBar {
409 | background-color: white;
410 | -webkit-transition: all 0.2s ease-out;
411 | -moz-transition: all 0.2s ease-out;
412 | -o-transition: all 0.2s ease-out;
413 | transition: all 0.2s ease-out;
414 | border-radius: 5px;
415 | }
416 | .progressjs-theme-blueOverlayRadiusWithPercentBar .progressjs-inner {
417 | height: 100%;
418 | -webkit-transition: all 0.3s ease-out;
419 | -moz-transition: all 0.3s ease-out;
420 | -o-transition: all 0.3s ease-out;
421 | transition: all 0.3s ease-out;
422 | background-color: #3498db;
423 | border-radius: 5px;
424 | }
425 | .progressjs-theme-blueOverlayRadiusWithPercentBar.progressjs-end {
426 | opacity: 0 !important;
427 | }
428 | .progressjs-theme-blueOverlayRadiusWithPercentBar .progressjs-percent {
429 | width: 70px;
430 | text-align: center;
431 | height: 40px;
432 | position: absolute;
433 | right: 50%;
434 | margin-right: -35px;
435 | top: 50%;
436 | margin-top: -20px;
437 | font-size: 30px;
438 | opacity: .5;
439 | }
440 |
441 | .progressjs-theme-blackRadiusInputs {
442 | height: 10px;
443 | border-radius: 10px;
444 | overflow: hidden;
445 | }
446 | .progressjs-theme-blackRadiusInputs .progressjs-inner {
447 | height: 2px;
448 | -webkit-transition: all 1s ease-out;
449 | -moz-transition: all 1s ease-out;
450 | -o-transition: all 1s ease-out;
451 | transition: all 1s ease-out;
452 | background-color: #34495e;
453 | }
454 | .progressjs-theme-blackRadiusInputs.progressjs-end {
455 | -webkit-transition: opacity 0.2s ease-out;
456 | -moz-transition: opacity 0.2s ease-out;
457 | -o-transition: opacity 0.2s ease-out;
458 | transition: opacity 0.2s ease-out;
459 | opacity: 0;
460 | }
461 | .progressjs-theme-blackRadiusInputs .progressjs-percent {
462 | display: none;
463 | }
464 |
--------------------------------------------------------------------------------
/static/weight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/weight.png
--------------------------------------------------------------------------------
/static/weight_ko.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carpedm20/voxoffice/4aa1a08351dba574455148ab3218a617d6bb2734/static/weight_ko.png
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 |
3 | {% block meta %}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
VoxOffice
12 | {% endblock %}
13 |
14 | {% block css %}
15 | .x.axis g text {
16 | fill: white;
17 | }
18 | {% endblock %}
19 |
20 | {% block navbar %}
21 |
VoxMusic
22 | {% endblock %}
23 |
24 | {% block script %}
25 |
26 | {% endblock %}
27 |
28 | {% block intro %}
29 |
30 |
31 |
32 |
33 |
A Data Visualization of Box Office History.
"What was the greatest movies in 2007?"
34 |
35 |
36 |
37 |
* View on Desktop, not on Mobile *
38 |
Github
39 |
Scroll down to enjoy yourself :)
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
The bigger, the better (Daily)
53 |
54 |
55 |
 }})
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
The darker, the better (Yearly)
64 |
65 |
66 |
 }})
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
 }})
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
두꺼울수록 인기가 있었던 영화 (하루 기준)
91 |
92 |
93 |
 }})
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
진할수록 인기가 있었던 영화 (1년 기준)
102 |
103 |
104 |
 }})
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
 }})
113 |
114 |
115 |
116 |
117 |
118 |
119 | {% endblock %}
120 |
121 | {% block sticker%}
122 |
123 |
124 |
125 |
139 |
149 |
160 |
185 |
188 |
189 | {% endblock %}
190 |
191 | {% block content %}
192 |
193 | {% for year in years %}
194 |
214 |
234 | {% endfor %}
235 |
236 | {% endblock %}
237 |
--------------------------------------------------------------------------------
/templates/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {% block meta %} {% endblock %}
7 |
8 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
36 |
37 |
38 |
39 |
40 |
47 |
57 |
58 | {% block intro %}{% endblock %}
59 |
60 |
61 |
62 |
63 | {% block sticker %}{% endblock %}
64 |
65 |
66 |
67 | {% block content %}{% endblock %}
68 |
69 |
70 |
71 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | {% block script %} {% endblock %}
116 |
117 |
118 |
--------------------------------------------------------------------------------
/templates/music.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 |
3 | {% block meta %}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
VoxMusic
12 | {% endblock %}
13 |
14 | {% block css %}
15 | .x.axis g text {
16 | fill: #34495e;
17 | font-weight: 600;
18 | }
19 | {% endblock %}
20 |
21 | {% block navbar %}
22 |
VoxOffice
23 | {% endblock %}
24 |
25 | {% block script %}
26 |
27 | {% endblock %}
28 |
29 | {% block intro %}
30 |
31 |
32 |
33 |
34 |
A Data Visualization of Music Chart History.
"What was the famous music in 2007?"
35 |
36 |
37 |
38 |
* View on Desktop, not on Mobile *
39 |
Github
40 |
Scroll down to enjoy yourself :)
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
The bigger, the better (Daily)
55 |
56 |
57 |
 }})
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
The darker, the better (Yearly)
66 |
67 |
68 |
 }})
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
두꺼울수록 인기가 있었던 음악 (하루 기준)
79 |
80 |
81 |
 }})
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
진할수록 인기가 있었던 음악 (1년 기준)
90 |
91 |
92 |
 }})
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | {% endblock %}
103 |
104 | {% block sticker%}
105 |
106 |
107 |
108 |
125 |
133 |
144 |
169 |
172 |
173 | {% endblock %}
174 |
175 | {% block content %}
176 |
177 | {% for year in years %}
178 |
198 |
218 | {% endfor %}
219 |
220 | {% endblock %}
221 |
--------------------------------------------------------------------------------