Changeset 159332 in webkit


Ignore:
Timestamp:
Nov 15, 2013 3:03:03 AM (10 years ago)
Author:
Antoine Quint
Message:

Web Inspector: New color picker
https://bugs.webkit.org/show_bug.cgi?id=124354

Reviewed by Timothy Hatcher.

Beginning of a new color picker. The focus of this new picker is to let you pick from
a color wheel as the primary mean of color picking, with additional slider controls for
the brightness and the opacity, better matching the default OS X color picker. This is the
basis for a color picker that will evolve to support the following:

Note also that the color wheel has not been tested on Retina displays
(see http://webkit.org/b/124355).

  • UserInterface/CSSColorPicker.css: Removed.
  • UserInterface/CSSColorPicker.js: Removed.

Previous color picker, now removed in favor of the new ColorPicker class.

  • UserInterface/CSSStyleDeclarationTextEditor.js:

Adopt new class name for the color picker, add a little padding to the popover
target frame and set the base color after the picker has been presented.

  • UserInterface/Color.js:

(WebInspector.Color.prototype._hslToRGB):
Simplified math.

(WebInspector.Color.rgb2hsv):
(WebInspector.Color.hsv2rgb):
New utilities to deal with HSV colors used in the ColorWheel.

  • UserInterface/ColorPicker.css: Added.
  • UserInterface/ColorPicker.js: Added.

(WebInspector.ColorPicker):
(WebInspector.ColorPicker.prototype.get element):
(WebInspector.ColorPicker.prototype.set brightness):
(WebInspector.ColorPicker.prototype.set opacity):
(WebInspector.ColorPicker.prototype.get color):

(WebInspector.ColorPicker.prototype.set color):
We set the _dontUpdateColor flag here such that we don't attempt to
notify about a color change at this point in case the selected color
is too saturated to be represented accurately on the color wheel and
we would end up changing the color by virtue of presenting the popover.

(WebInspector.ColorPicker.prototype.colorWheelColorDidChange):
(WebInspector.ColorPicker.prototype.sliderValueDidChange):
(WebInspector.ColorPicker.prototype._updateColor):
(WebInspector.ColorPicker.prototype._updateSliders):

  • UserInterface/ColorWheel.css: Added.
  • UserInterface/ColorWheel.js: Added.

The ColorWheel makes use of three different <canvas> elements to draw itself.
The "raw" canvas is used to draw the raw, un-tinted color wheel with poor
aliasing. The "raw" canvas is only drawn when the dimension is changed.
The "tinted" canvas is used to draw the "raw" canvas with a black overlay
based on the brightness set on the wheel. The "final" canvas, the only <canvas>
element attached to the DOM, is used to draw the "tinted" canvas into a circle
clip of a slightly narrower radius so that the drawn image is visually more pleasing
and can be displayed above virtually any background color.

We use color math to generate the color wheel, courtesy of Dean Jackson, and also to
figure out where to position the crosshair for the provided base color as well as
the opposite operation where we get the color under the mouse pointer.

The color wheel fires a single delegate method call colorWheelColorDidChange(colorWheel),
the colors themselves being retrieved via the public properties tintedColor and rawColor.

(WebInspector.ColorWheel):
(WebInspector.ColorWheel.prototype.set dimension):
(WebInspector.ColorWheel.prototype.get element):
(WebInspector.ColorWheel.prototype.get brightness):
(WebInspector.ColorWheel.prototype.set brightness):
(WebInspector.ColorWheel.prototype.get tintedColor):
(WebInspector.ColorWheel.prototype.set tintedColor):
(WebInspector.ColorWheel.prototype.get rawColor):
(WebInspector.ColorWheel.prototype.handleEvent):
(WebInspector.ColorWheel.prototype._handleMousedown):
(WebInspector.ColorWheel.prototype._handleMousemove):
(WebInspector.ColorWheel.prototype._handleMouseup):
(WebInspector.ColorWheel.prototype._pointInCircleForEvent):
(WebInspector.ColorWheel.prototype._pointInCircleForEvent.angleFromCenterToPoint):
(WebInspector.ColorWheel.prototype._pointInCircleForEvent.pointOnCircumference):
(WebInspector.ColorWheel.prototype._updateColorForMouseEvent):
(WebInspector.ColorWheel.prototype._setCrosshairPosition):
(WebInspector.ColorWheel.prototype._tintedColorToPointAndBrightness):
(WebInspector.ColorWheel.prototype._drawRawCanvas):
(WebInspector.ColorWheel.prototype._colorAtPointWithBrightness):
(WebInspector.ColorWheel.prototype._drawTintedCanvas):
(WebInspector.ColorWheel.prototype._draw):

  • UserInterface/Images/SliderThumb.png: Added.
  • UserInterface/Images/SliderThumb@2x.png: Added.
  • UserInterface/Images/SliderThumbPressed.png: Added.
  • UserInterface/Images/SliderThumbPressed@2x.png: Added.

Supporting artwork for the new Slider class.

  • UserInterface/Main.html:

Remove the previous color picker class and add the new one, as well as the new Slider class.

  • UserInterface/Slider.css: Added.
  • UserInterface/Slider.js: Added.

New slider to match the look of the sliders used in the native OS X color picker. The most
interesting feature of these sliders is that they can be transformed using CSS in any way
and will still operate correctly due to always converting the mouse coordinates in the page
coordinate system to the coordinate system local to the backing element. For instance, the
color picker uses two sliders transformed to be displayed vertically.

As it stands these slides only support values between 0 and 1 and fire a single delegate
method call sliderValueDidChange(slider, newValue).

(WebInspector.Slider):
(WebInspector.Slider.prototype.get element):
(WebInspector.Slider.prototype.get value):
(WebInspector.Slider.prototype.set value):
(WebInspector.Slider.prototype.handleEvent):
(WebInspector.Slider.prototype._handleMousedown):
(WebInspector.Slider.prototype._handleMousemove):
(WebInspector.Slider.prototype._handleMouseup):
(WebInspector.Slider.prototype._localPointForEvent):
(WebInspector.Slider.prototype.get _maxX):

  • WebInspectorUI.vcxproj/WebInspectorUI.vcxproj:
  • WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters:

Update file names for the new color picker.

Location:
trunk/Source/WebInspectorUI
Files:
10 added
2 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r159286 r159332  
     12013-11-15  Antoine Quint  <graouts@apple.com>
     2
     3        Web Inspector: New color picker
     4        https://bugs.webkit.org/show_bug.cgi?id=124354
     5
     6        Reviewed by Timothy Hatcher.
     7
     8        Beginning of a new color picker. The focus of this new picker is to let you pick from
     9        a color wheel as the primary mean of color picking, with additional slider controls for
     10        the brightness and the opacity, better matching the default OS X color picker. This is the
     11        basis for a color picker that will evolve to support the following:
     12
     13        - editable CSS value label (http://webkit.org/b/124356)
     14        - picking a color anywhere on screen (http://webkit.org/b/124357)
     15        - swatches based on other colors in page (http://webkit.org/b/124358)
     16
     17        Note also that the color wheel has not been tested on Retina displays
     18        (see http://webkit.org/b/124355).
     19
     20        * UserInterface/CSSColorPicker.css: Removed.
     21        * UserInterface/CSSColorPicker.js: Removed.
     22        Previous color picker, now removed in favor of the new ColorPicker class.
     23
     24        * UserInterface/CSSStyleDeclarationTextEditor.js:
     25        Adopt new class name for the color picker, add a little padding to the popover
     26        target frame and set the base color after the picker has been presented.
     27
     28        * UserInterface/Color.js:
     29        (WebInspector.Color.prototype._hslToRGB):
     30        Simplified math.
     31
     32        (WebInspector.Color.rgb2hsv):
     33        (WebInspector.Color.hsv2rgb):
     34        New utilities to deal with HSV colors used in the ColorWheel.
     35
     36        * UserInterface/ColorPicker.css: Added.
     37
     38        * UserInterface/ColorPicker.js: Added.
     39        (WebInspector.ColorPicker):
     40        (WebInspector.ColorPicker.prototype.get element):
     41        (WebInspector.ColorPicker.prototype.set brightness):
     42        (WebInspector.ColorPicker.prototype.set opacity):
     43        (WebInspector.ColorPicker.prototype.get color):
     44
     45        (WebInspector.ColorPicker.prototype.set color):
     46        We set the _dontUpdateColor flag here such that we don't attempt to
     47        notify about a color change at this point in case the selected color
     48        is too saturated to be represented accurately on the color wheel and
     49        we would end up changing the color by virtue of presenting the popover.
     50
     51        (WebInspector.ColorPicker.prototype.colorWheelColorDidChange):
     52        (WebInspector.ColorPicker.prototype.sliderValueDidChange):
     53        (WebInspector.ColorPicker.prototype._updateColor):
     54        (WebInspector.ColorPicker.prototype._updateSliders):
     55
     56        * UserInterface/ColorWheel.css: Added.
     57
     58        * UserInterface/ColorWheel.js: Added.
     59        The ColorWheel makes use of three different <canvas> elements to draw itself.
     60        The "raw" canvas is used to draw the raw, un-tinted color wheel with poor
     61        aliasing. The "raw" canvas is only drawn when the dimension is changed.
     62        The "tinted" canvas is used to draw the "raw" canvas with a black overlay
     63        based on the brightness set on the wheel. The "final" canvas, the only <canvas>
     64        element attached to the DOM, is used to draw the "tinted" canvas into a circle
     65        clip of a slightly narrower radius so that the drawn image is visually more pleasing
     66        and can be displayed above virtually any background color.
     67
     68        We use color math to generate the color wheel, courtesy of Dean Jackson, and also to
     69        figure out where to position the crosshair for the provided base color as well as
     70        the opposite operation where we get the color under the mouse pointer.
     71
     72        The color wheel fires a single delegate method call colorWheelColorDidChange(colorWheel),
     73        the colors themselves being retrieved via the public properties tintedColor and rawColor.
     74
     75        (WebInspector.ColorWheel):
     76        (WebInspector.ColorWheel.prototype.set dimension):
     77        (WebInspector.ColorWheel.prototype.get element):
     78        (WebInspector.ColorWheel.prototype.get brightness):
     79        (WebInspector.ColorWheel.prototype.set brightness):
     80        (WebInspector.ColorWheel.prototype.get tintedColor):
     81        (WebInspector.ColorWheel.prototype.set tintedColor):
     82        (WebInspector.ColorWheel.prototype.get rawColor):
     83        (WebInspector.ColorWheel.prototype.handleEvent):
     84        (WebInspector.ColorWheel.prototype._handleMousedown):
     85        (WebInspector.ColorWheel.prototype._handleMousemove):
     86        (WebInspector.ColorWheel.prototype._handleMouseup):
     87        (WebInspector.ColorWheel.prototype._pointInCircleForEvent):
     88        (WebInspector.ColorWheel.prototype._pointInCircleForEvent.angleFromCenterToPoint):
     89        (WebInspector.ColorWheel.prototype._pointInCircleForEvent.pointOnCircumference):
     90        (WebInspector.ColorWheel.prototype._updateColorForMouseEvent):
     91        (WebInspector.ColorWheel.prototype._setCrosshairPosition):
     92        (WebInspector.ColorWheel.prototype._tintedColorToPointAndBrightness):
     93        (WebInspector.ColorWheel.prototype._drawRawCanvas):
     94        (WebInspector.ColorWheel.prototype._colorAtPointWithBrightness):
     95        (WebInspector.ColorWheel.prototype._drawTintedCanvas):
     96        (WebInspector.ColorWheel.prototype._draw):
     97
     98        * UserInterface/Images/SliderThumb.png: Added.
     99        * UserInterface/Images/SliderThumb@2x.png: Added.
     100        * UserInterface/Images/SliderThumbPressed.png: Added.
     101        * UserInterface/Images/SliderThumbPressed@2x.png: Added.
     102        Supporting artwork for the new Slider class.
     103
     104        * UserInterface/Main.html:
     105        Remove the previous color picker class and add the new one, as well as the new Slider class.
     106
     107        * UserInterface/Slider.css: Added.
     108
     109        * UserInterface/Slider.js: Added.
     110        New slider to match the look of the sliders used in the native OS X color picker. The most
     111        interesting feature of these sliders is that they can be transformed using CSS in any way
     112        and will still operate correctly due to always converting the mouse coordinates in the page
     113        coordinate system to the coordinate system local to the backing element. For instance, the
     114        color picker uses two sliders transformed to be displayed vertically.
     115
     116        As it stands these slides only support values between 0 and 1 and fire a single delegate
     117        method call sliderValueDidChange(slider, newValue).
     118
     119        (WebInspector.Slider):
     120        (WebInspector.Slider.prototype.get element):
     121        (WebInspector.Slider.prototype.get value):
     122        (WebInspector.Slider.prototype.set value):
     123        (WebInspector.Slider.prototype.handleEvent):
     124        (WebInspector.Slider.prototype._handleMousedown):
     125        (WebInspector.Slider.prototype._handleMousemove):
     126        (WebInspector.Slider.prototype._handleMouseup):
     127        (WebInspector.Slider.prototype._localPointForEvent):
     128        (WebInspector.Slider.prototype.get _maxX):
     129
     130        * WebInspectorUI.vcxproj/WebInspectorUI.vcxproj:
     131        * WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters:
     132        Update file names for the new color picker.
     133
    11342013-11-14  Antoine Quint  <graouts@apple.com>
    2135
  • trunk/Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js

    r156923 r159332  
    744744            this._colorPickerPopover = new WebInspector.Popover(this);
    745745
    746             var colorPicker = new WebInspector.CSSColorPicker;
    747             colorPicker.color = color;
    748 
    749             colorPicker.addEventListener(WebInspector.CSSColorPicker.Event.ColorChanged, function(event) {
     746            var colorPicker = new WebInspector.ColorPicker;
     747
     748            colorPicker.addEventListener(WebInspector.ColorPicker.Event.ColorChanged, function(event) {
    750749                updateCodeMirror.call(this, event.data.color.toString());
    751750            }.bind(this));
    752751
    753752            var bounds = WebInspector.Rect.rectFromClientRect(swatch.getBoundingClientRect());
     753            const padding = 2;
     754            bounds.origin.x -= padding;
     755            bounds.origin.y -= padding;
     756            bounds.size.width += padding * 2;
     757            bounds.size.height += padding * 2;
    754758
    755759            this._colorPickerPopover.content = colorPicker.element;
    756760            this._colorPickerPopover.present(bounds, [WebInspector.RectEdge.MIN_X]);
    757761
    758             colorPicker.shown();
     762            colorPicker.color = color;
    759763        }
    760764    },
  • trunk/Source/WebInspectorUI/UserInterface/Color.js

    r158439 r159332  
    414414        var l = parseFloat(hsl[2]) / 100;
    415415
    416         if (s < 0)
    417             s = 0;
    418 
    419         if (l <= 0.5)
    420             var q = l * (1 + s);
    421         else
    422             var q = l + s - (l * s);
    423 
    424         var p = 2 * l - q;
    425 
    426         var tr = h + (1 / 3);
    427         var tg = h;
    428         var tb = h - (1 / 3);
    429 
    430         var r = Math.round(hueToRGB(p, q, tr) * 255);
    431         var g = Math.round(hueToRGB(p, q, tg) * 255);
    432         var b = Math.round(hueToRGB(p, q, tb) * 255);
    433         return [r, g, b];
    434 
    435         function hueToRGB(p, q, h) {
    436             if (h < 0)
    437                 h += 1;
    438             else if (h > 1)
    439                 h -= 1;
    440 
    441             if ((h * 6) < 1)
    442                 return p + (q - p) * h * 6;
    443             else if ((h * 2) < 1)
    444                 return q;
    445             else if ((h * 3) < 2)
    446                 return p + (q - p) * ((2 / 3) - h) * 6;
    447             else
    448                 return p;
    449         }
     416        h *= 6;
     417        var sArray = [
     418            l += s *= l < .5 ? l : 1 - l,
     419            l - h % 1 * s * 2,
     420            l -= s *= 2,
     421            l,
     422            l + h % 1 * s,
     423            l + s
     424        ];
     425        return [
     426            Math.round(sArray[ ~~h    % 6 ] * 255),
     427            Math.round(sArray[ (h|16) % 6 ] * 255),
     428            Math.round(sArray[ (h|8)  % 6 ] * 255)
     429        ];
    450430    },
    451431
     
    852832    "hsla(0,0,0,0)": [[0, 0, 0, 0], [0, 0, 0, 0], "transparent"],
    853833};
     834
     835WebInspector.Color.rgb2hsv = function(r, g, b)
     836{
     837    r /= 255;
     838    g /= 255;
     839    b /= 255;
     840
     841    var min = Math.min(Math.min(r, g), b);
     842    var max = Math.max(Math.max(r, g), b);
     843    var delta = max - min;
     844
     845    var v = max;
     846    var s, h;
     847
     848    if (max === min)
     849        h = 0;
     850    else if (max === r)
     851        h = (60 * ((g - b) / delta)) % 360;
     852    else if (max === g)
     853        h = 60 * ((b - r) / delta) + 120;
     854    else if (max === b)
     855        h = 60 * ((r - g) / delta) + 240;
     856
     857    if (h < 0)
     858        h += 360;
     859
     860    // Saturation
     861    if (max === 0)
     862        s = 0;
     863    else
     864        s = 1 - (min/max);
     865
     866    return [h, s, v];
     867}
     868
     869WebInspector.Color.hsv2rgb = function(h, s, v)
     870{
     871    if (s === 0)
     872        return [v, v, v];
     873
     874    h /= 60;
     875    var i = Math.floor(h);
     876    var data = [
     877        v * (1 - s),
     878        v * (1 - s * (h - i)),
     879        v * (1 - s * (1 - (h - i)))
     880    ];
     881    var rgb;
     882
     883    switch (i) {
     884    case 0:
     885        rgb = [v, data[2], data[0]];
     886        break;
     887    case 1:
     888        rgb = [data[1], v, data[0]];
     889        break;
     890    case 2:
     891        rgb = [data[0], v, data[2]];
     892        break;
     893    case 3:
     894        rgb = [data[0], data[1], v];
     895        break;
     896    case 4:
     897        rgb = [data[2], data[0], v];
     898        break;
     899    default:
     900        rgb = [v, data[0], data[1]];
     901        break;
     902    }
     903
     904    return rgb;
     905}
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r159151 r159332  
    119119    <link rel="stylesheet" href="CodeMirrorOverrides.css">
    120120    <link rel="stylesheet" href="ConsolePrompt.css">
    121     <link rel="stylesheet" href="CSSColorPicker.css">
     121    <link rel="stylesheet" href="Slider.css">
     122    <link rel="stylesheet" href="ColorWheel.css">
     123    <link rel="stylesheet" href="ColorPicker.css">
    122124    <link rel="stylesheet" href="CodeMirrorDragToAlterNumberController.css">
    123125    <link rel="stylesheet" href="GoToLineDialog.css">
     
    322324    <script src="RulesStyleDetailsPanel.js"></script>
    323325    <script src="MetricsStyleDetailsPanel.js"></script>
    324     <script src="CSSColorPicker.js"></script>
     326    <script src="Slider.js"></script>
     327    <script src="ColorWheel.js"></script>
     328    <script src="ColorPicker.js"></script>
    325329    <script src="CSSStyleDeclarationTextEditor.js"></script>
    326330    <script src="CSSStyleDeclarationSection.js"></script>
  • trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj

    r157600 r159332  
    1 <?xml version="1.0" encoding="utf-8"?>
     1<?xml version="1.0" encoding="utf-8"?>
    22<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    33  <ItemGroup Label="ProjectConfigurations">
     
    215215    <None Include="..\UserInterface\CookieStorageObject.js" />
    216216    <None Include="..\UserInterface\CookieStorageTreeElement.js" />
    217     <None Include="..\UserInterface\CSSColorPicker.css" />
    218     <None Include="..\UserInterface\CSSColorPicker.js" />
     217    <None Include="..\UserInterface\ColorPicker.css" />
     218    <None Include="..\UserInterface\ColorPicker.js" />
    219219    <None Include="..\UserInterface\CSSCompletions.js" />
    220220    <None Include="..\UserInterface\CSSKeywordCompletions.js" />
  • trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters

    r157600 r159332  
    250250      <Filter>UserInterface</Filter>
    251251    </None>
    252     <None Include="..\UserInterface\CSSColorPicker.css">
    253       <Filter>UserInterface</Filter>
    254     </None>
    255     <None Include="..\UserInterface\CSSColorPicker.js">
     252    <None Include="..\UserInterface\ColorPicker.css">
     253      <Filter>UserInterface</Filter>
     254    </None>
     255    <None Include="..\UserInterface\ColorPicker.js">
    256256      <Filter>UserInterface</Filter>
    257257    </None>
Note: See TracChangeset for help on using the changeset viewer.