OSDN Git Service

update at 12/23/2018
[sawarabi-fonts/sawarabi-fonts.git] / html / coffee / doc-header.coffee
1 Canvas =
2   el: "canvas#header-canvas"
3   generateContext: ->
4     @$el = $(@el)
5     cvs = @$el.get(0)
6     @context = if cvs and cvs.getContext then cvs.getContext('2d') else null
7     @ctx = @context
8     @ctx.save() if @ctx
9
10 class Screen
11   constructor: (attr={}) ->
12     @width = attr.width
13     @height = attr.height
14     @objects = []
15     @locking = false
16
17   clear: ->
18     Canvas.ctx.clearRect(0, 0, @width, @height)
19     Canvas.ctx.restore()
20     Canvas.ctx.save()
21     @objects = []
22
23   add: (obj) ->
24     @objects.push(obj)
25
26   draw: (obj) ->
27     if obj
28       obj.draw()
29     else
30       x.draw() for x in @objects
31     @
32
33   animate: ->
34     @locking = true
35     setTimeout =>
36       animating = false
37       for x in @objects when x.isAnimating? and x.isAnimating()
38         x.draw()
39         animating = true
40       if animating then @animate() else @afterAnimation()
41     , 25
42   afterAnimation: ->
43     @locking = false
44     x.afterAnimation(@) for x in @objects when x.afterAnimation?
45
46 class Label
47   constructor: (text, attr={}) ->
48     @text = text
49     merge(@, attr)
50     @font ?= '10px sans'
51     @color ?= 'white'
52     @x ?= 0
53     @y ?= 0
54
55   getWidth: ->
56     Canvas.ctx.font = @font
57     Canvas.ctx.measureText(@text).width
58
59   draw: (offsetX=0, offsetY=0) ->
60     pos = screenPosition @, offsetX, offsetY
61     Canvas.ctx.font = @font
62     Canvas.ctx.fillStyle = @color
63     Canvas.ctx.fillText @text, pos.x, pos.y
64
65 class Line
66   constructor: (attr={}) ->
67     @x0 = attr.x0 or attr.x or 0
68     @y0 = attr.y0 or attr.y or 0
69     @x1 = attr.x1 or attr.x or 0
70     @y1 = attr.y1 or attr.y or 0
71     @color = attr.color or '#fff'
72
73   draw: (offsetX=0, offsetY=0) ->
74     pos = screenPosition @, offsetX, offsetY
75     c = Canvas.ctx
76     c.beginPath()
77     c.strokeStyle = @color
78     c.moveTo pos.x0, pos.y0
79     c.lineTo pos.x1, pos.y1
80     c.stroke()
81     c.closePath()
82
83 class AbstractRectangle
84   constructor: (attr={}) ->
85     merge(@, attr)
86     @x0 ?= 0
87     @y0 ?= 0
88     @x1 ?= 0
89     @y1 ?= 0
90
91   draw: (offsetX=0, offsetY=0) ->
92     pos = screenPosition @, offsetX, offsetY
93     Canvas.ctx.beginPath()
94     Canvas.ctx.rect(pos.x0, pos.y0, pos.x1 - pos.x0, pos.y1 - pos.y0)
95
96 class GradientRectangle extends AbstractRectangle
97   constructor: (attr={}) ->
98     super(attr)
99     @colors ?= ['#fff', '#fff']
100     @direction ?= 'horizontal'
101
102   draw: (offsetX=0, offsetY=0) ->
103     c = Canvas.ctx
104     p = screenPosition(@, offsetX, offsetY)
105     g = null
106     if @direction is 'vertical'
107       g = c.createLinearGradient(p.x0, p.y0, p.x0, p.y1)
108     else if @direction is 'horizontal'
109       g = c.createLinearGradient(p.x0, p.y0, p.x1, p.y0)
110     d = 0.0
111     for v in @colors
112       g.addColorStop(d, v)
113       d += 1 / (@colors.length - 1)
114     c.fillStyle = g
115     super(offsetX, offsetY)
116     c.fill()
117
118 class GraphBar
119   constructor: (attr={}) ->
120     merge @, attr
121     @x ?= 0
122     @y ?= 0
123     @width ?= 1
124     @height ?= 24
125     @performance = attr.performance or 0
126     @max = attr.max or 1
127     @frame = 0.0
128     @frames = 10.0
129
130   draw: (offsetX=0, offsetY=0) ->
131     width = (@width * 1.0) / @max * @performance * @frame / @frames
132     c = Canvas.ctx
133     c.beginPath()
134     if @frame is @frames
135       c.shadowBlur = 4
136       c.shadowOffsetY = 2
137       c.shadowColor = "rgba(0, 0, 0, 0.4)"
138     pos = screenPosition @, offsetX, offsetY
139     g = c.createLinearGradient(pos.x, pos.y, pos.x, pos.y + @height)
140     g.addColorStop 0.0, "#fc8a27"
141     g.addColorStop 0.1, "#fcb229"
142     g.addColorStop 0.4, "#fc8a29"
143     g.addColorStop 1.0, "#e97122"
144     c.fillStyle = g
145     c.rect(pos.x, pos.y, width, @height)
146     c.fill()
147
148   isAnimating: ->
149     @frame += 1
150     @frame <= @frames
151
152   afterAnimation: (screen) ->
153     rate = 100.0 * @performance / @max
154     val = rate.toFixed(2)
155     val = parseInt(val) if parseInt(val) * 1.0 is Number(val)
156     label = new Label "#{val}%",
157       font: '12px sans'
158     width = 1.0 * @width / @max * @performance
159     x = (width - label.getWidth()) / 2
160     x = width + 10 if x < 5
161     label.x = x + @x
162     label.y = @height / 2 + 4 + @y
163     screen.draw label
164
165 merge = (dist, src) ->
166   dist[k] = v for k, v of src when src.hasOwnProperty(k)
167
168 screenPosition = (obj, offsetX, offsetY) ->
169   pos = {}
170   offset =
171     x: offsetX
172     y: offsetY
173   for m in screenPosition.fields when obj.hasOwnProperty(m)
174     pos[m] = obj[m] + offset[m[0]]
175   pos
176 screenPosition.fields = ['x', 'y', 'x0', 'y0', 'x1', 'y1']
177
178 KanjiInfo =
179   max:
180     kyoikuKanji: 1006
181     level1st: 2965
182     level2nd: 3390
183     level3rd: 1259
184     level4th: 2436
185   update: (callback) ->
186     exec = (type, func) ->
187       $.ajax 
188         type: 'GET'
189         url: '/cgi-bin/num-of-kanjis.cgi'
190         data: "type=#{type}"
191         dataType: 'json'
192         success: (data, dataType) ->
193           KanjiInfo[type] = data
194           func()
195         error: (request, textStatus, errorThrown) ->
196           alert(textStatus)
197
198     exec 'gothic', ->
199       exec 'mincho', callback
200
201 makeGraphPage = (screen, pageName) ->
202   # title
203   do ->
204     titleLabel = new Label window.dictionary.title,
205       x: 30
206       y: 36
207       font: '21px sans'
208     fontLabel = new Label window.dictionary.fonts[pageName],
209       x: 30 + titleLabel.getWidth()
210       y: 36
211       font: '14px sans'
212     bottomLine = new Line y: 53, x0: 0, x1: 680
213
214     screen.add titleLabel
215     screen.add fontLabel
216     screen.add bottomLine
217
218   # Graph Area
219   do ->
220     graphArea = new GradientRectangle
221       x0: 146
222       y0: 75
223       x1: 650
224       y1: 268
225       colors: [
226         'rgba(0, 0, 0, 0.25)'
227         'rgba(0, 0, 0, 0.1)'
228       ] 
229
230     screen.add graphArea
231
232     d = [650 - 146] / 4
233     for _, x in new Array(5)
234       screen.add new Line
235         x: 146 + d * (x + 1)
236         y0: 75
237         y1: 268
238         color: "rgb(178, 255, 178)"
239
240   # Graph bars
241   do ->
242     fields = [
243       'kyoikuKanji'
244       'level1st'
245       'level2nd'
246       'level3rd'
247       'level4th'
248       ]
249
250     for field, n in fields
251       screen.add new Label window.dictionary[field],
252         x: 30
253         y: 103 + (37 * n)
254         font: '14px sans'
255
256       screen.add new GraphBar
257         x: 146
258         y: 87 + (37 * n)
259         width: 504
260         max: KanjiInfo.max[field]
261         performance: KanjiInfo[pageName][field]
262
263   # Graph base line
264   screen.add new Line
265     x: 146,
266     y0: 75
267     y1: 268
268     color: "rgb(255, 255, 255)"
269
270   screen
271
272 $ ->
273   Canvas.generateContext()
274   return unless Canvas.ctx
275
276   screenScale = (->
277     scale = {}
278     scale[m] = parseInt(Canvas.$el.css(m)) for m in ['width', 'height']
279     scale
280   )()
281
282   screen = new Screen screenScale
283
284   KanjiInfo.update ->
285     drawPage = (pageIndex) ->
286       pageName = drawPage.mapping[pageIndex]
287       makeGraphPage(screen, pageName).draw().animate() if pageName
288     drawPage.mapping = [
289       'gothic'
290       'mincho'
291     ]
292
293     $container = $('#docs-header .buttons-container .inner-container')
294     buttons = []
295     for name, n in drawPage.mapping
296       b = document.createElement('div')
297       $(b).addClass('button').text(n + 1).click ->
298         return if screen.locking or $(@).hasClass('pressed')
299         screen.clear()
300         index = parseInt($(@).text() - 1)
301         name = drawPage.mapping[parseInt($(@).text() - 1)]
302         makeGraphPage(screen, name).draw().animate() if name
303         buttons.forEach (x) -> $(x).removeClass('pressed')
304         $(@).addClass('pressed')
305       $container.append(b)
306       buttons.push(b)
307
308     drawPage(0)
309     $(buttons[0]).addClass('pressed')