ui/js/coffee/charts_punchcard.coffee (79 lines of code) (raw):
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
punchcard_color = (p, MAX) ->
v = (p/MAX)
hue=((1-v)*120).toString(10)
return "hsl(#{hue},80%,40%)"
pval = (d,m) ->
v = Math.max(d, m/3)
if v > m/3
v = (v+(m/3)) / m
else
v = 0.33
charts_punchcard = (obj, data, options) ->
div = document.getElementById('tooltip_punchcard')
if not div
div = d3.select("body").append("div").attr("class", "punchcard_tooltip").attr('id', 'tooltip_punchcard').style("opacity", 0)
else
div = d3.select(div)
data = data.timeseries
days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
c = []
chart = d3.select(obj).append("svg").attr("width", '100%').attr("height", '100%')
MAX = 0
for k, v of data
m = k.split(/ - /)
a = m[0]
b = m[1]
ypos = 0
if b == '24'
b = 0
xpos = 0.1 + (parseInt(b) ) * (0.036)
for n,d of days
if d == a
ypos = 0.04 + (n * 0.10)
c.push({x: xpos, y: ypos, r: v, h: "<span style='font-size:0.9rem;'>#{a}, #{b}:00 -> #{(parseInt(b)+1) % 24}:00 UTC</span><br/>"})
MAX = Math.max(MAX, v)
circles = chart.selectAll('svg').data(c).enter().append("circle");
labels = chart.selectAll('svg').data(days).enter().append('text')
slots = chart.selectAll('svg').data([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]).enter().append('text')
redraw = () ->
xy = obj.getBoundingClientRect()
xy.height = xy.width * 0.5
chart.attr('width', xy.width + 'px')
chart.attr('height', xy.height + 'px')
maxr = Math.sqrt(xy.width**2 + xy.height**2) / 80
cw = (0.03*xy.width)
circles.attr("cx", (d) => (d.x*xy.width) + cw/2).attr("cy", (d) => 50 + d.y*xy.height ).attr("r", (d) => pval(d.r, MAX) * maxr).style("fill", (d) => punchcard_color(d.r, MAX)).
on("mouseover", (d) ->
div.transition()
.duration(200)
.style("opacity", .9)
div .html(d.h + d.r.pretty() + " commits")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
).on("mouseout", (d) ->
div.transition()
.duration(200)
.style("opacity", 0)
)
labels.attr('x', 20).attr('y', (d) => (55 + (0.04 + days.indexOf(d) * 0.10) * xy.height)).attr('font-size', maxr*1.75).text((d) => d)
slots.attr('x', (d) => (0.1 + d * 0.036) * xy.width + cw/2).attr('y',38).attr('text-anchor', 'middle').attr('width', cw).attr('font-size', maxr*1.5).text((d) => d)
chart.node().addEventListener("resize", redraw)
window.addEventListener("resize", redraw)
redraw();
return [chart, {punchcard: true}]