1<?php
2
3/**
4 * Represents a palette of indexed graph colors
5 *
6 */
7class Palette {
8    /** @todo Are the keys on this array always numbers, and always
9     * sequential?  That's the way it's used in the code, but I don't
10     * think we enforce that anywhere. Is enforcing it a sensible
11     * thing to do? */
12    public $colors = array();
13
14    /**
15     * Return the 7 color standard palette
16     *
17     * @static
18     * @return Palette
19     */
20    static public function defaultPalette() {
21        $palette = new Palette;
22
23        $palette->colors = array(
24            0 => new Color(188, 224, 46),
25            1 => new Color(224, 100, 46),
26            2 => new Color(224, 214, 46),
27            3 => new Color(46, 151, 224),
28            4 => new Color(176, 46, 224),
29            5 => new Color(224, 46, 117),
30            6 => new Color(92, 224, 46),
31            7 => new Color(224, 176, 46)
32        );
33
34        return $palette;
35    }
36
37    /**
38     * Creates a palette from a gradient between $color1 and $color2
39     *
40     * @static
41     * @param Color $color1 start color
42     * @param Color $color2 end color
43     * @param int   $shades number of colors to create
44     * @return Palette
45     */
46    static public function colorGradientPalette(Color $color1, Color $color2, $shades) {
47        $palette = new Palette();
48
49        $RFactor = ($color2->getR() - $color1->getR()) / $shades;
50        $GFactor = ($color2->getG() - $color1->getG()) / $shades;
51        $BFactor = ($color2->getB() - $color1->getB()) / $shades;
52
53        for($i = 0; $i <= $shades - 1; $i++) {
54            $palette->colors[$i] = new Color($color1->getR() + $RFactor * $i,
55                                             $color1->getG() + $GFactor * $i,
56                                             $color1->getB() + $BFactor * $i);
57        }
58
59        return $palette;
60    }
61
62    /**
63     * Create a color palette from a file
64     *
65     * @static
66     * @param string $filename
67     * @param string $delimiter
68     * @throws Exception
69     * @return Palette
70     */
71    static public function fromFile($filename, $delimiter = ',') {
72        $handle = @fopen($filename, 'r');
73        if(!$handle) throw new Exception('Failed to open file in loadColorPalette');
74
75        $palette = new Palette();
76        $idx = 0;
77        while(!feof($handle)) {
78            $buffer = fgets($handle, 4096);
79            $buffer = str_replace(chr(10), '', $buffer);
80            $buffer = str_replace(chr(13), '', $buffer);
81            $values = explode($delimiter, $buffer);
82            $values = array_map('trim', $values);
83            if(count($values) == 3) {
84                $palette->setColor($idx, new Color($values[0], $values[1], $values[2]));
85                $idx++;
86            }elseif(count($values) == 1 && $values[0] !== ''){
87                $palette->setColor($idx, new Color($values[0]));
88            }
89        }
90        return $palette;
91    }
92
93    /**
94     * Set the color at the specified position
95     *
96     * @param int   $id
97     * @param Color $color
98     */
99    public function setColor($id, Color $color) {
100        $this->colors[$id] = $color;
101    }
102
103    /**
104     * Get the color at the specified position
105     *
106     * @param int $id position in the color array
107     * @return Color
108     */
109    public function getColor($id) {
110        if(isset($this->colors[$id])) return $this->colors[$id];
111
112        // there's no color assigned, create a pseudo random one
113        $this->colors[$id] = Color::random($id);
114        return $this->colors[$id];
115    }
116}