lib/spoom/coverage/d3.rb



# typed: strict
# frozen_string_literal: true

require_relative "d3/circle_map"
require_relative "d3/pie"
require_relative "d3/timeline"

module Spoom
  module Coverage
    module D3
      extend T::Sig

      COLOR_IGNORE = "#999"
      COLOR_FALSE = "#db4437"
      COLOR_TRUE = "#0f9d58"
      COLOR_STRICT = "#0a7340"
      COLOR_STRONG = "#064828"

      sig { returns(String) }
      def self.header_style
        <<~CSS
          svg {
            width: 100%;
            height: 100%;
          }

          .tooltip {
            font: 12px Arial, sans-serif;
            color: #fff;
            text-align: center;
            background: rgba(0, 0, 0, 0.6);
            padding: 5px;
            border: 0px;
            border-radius: 4px;
            position: absolute;
            top: 0;
            left: 0;
            opacity: 0;
          }

          .label {
            font: 14px Arial, sans-serif;
            font-weight: bold;
            fill: #fff;
            text-anchor: middle;
            pointer-events: none;
          }

          .label .small {
            font-size: 10px;
          }

          #{Pie.header_style}
          #{CircleMap.header_style}
          #{Timeline.header_style}
        CSS
      end

      sig { params(palette: ColorPalette).returns(String) }
      def self.header_script(palette)
        <<~JS
          var parseDate = d3.timeParse("%s");

          function strictnessColor(strictness) {
            switch(strictness) {
              case "ignore":
                return "#{palette.ignore}";
              case "false":
                return "#{palette.false}";
              case "true":
                return "#{palette.true}";
              case "strict":
                return "#{palette.strict}";
              case "strong":
                return "#{palette.strong}";
            }
            return "#{palette.false}";
          }

          function toPercent(value, sum) {
            return value ? Math.round(value * 100 / sum) : 0;
          }

          var tooltip = d3.select("body")
            .append("div")
              .append("div")
                .attr("class", "tooltip");

          function moveTooltip(d) {
            return tooltip
              .style("left", (d3.event.pageX + 20) + "px")
              .style("top", (d3.event.pageY) + "px")
          }

          #{Pie.header_script}
          #{CircleMap.header_script}
          #{Timeline.header_script}
        JS
      end

      class ColorPalette < T::Struct
        prop :ignore, String
        prop :false, String
        prop :true, String
        prop :strict, String
        prop :strong, String
      end
    end
  end
end