Wpf ArcSegment с 3-х цветным градиентом - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь нарисовать ArcSegment в своем элементе управления WPF, который используется как индикатор циклического прогресса и имеет трехцветный градиент.Следует начинать с красного на 0%, желтого на 50% и зеленого на 100%.Таким образом, для 75% это должно выглядеть так:

Like is should look like

Я пробую это с LinearGradientBrush

<Path StrokeThickness="25">
    <Path.Data>
        <PathGeometry>
            <PathFigure StartPoint="50, 12.5">

                <ArcSegment RotationAngle="0" SweepDirection="Clockwise"
                            IsLargeArc="true"
                            Point="12.5, 75" 
                            Size="62.5, 62.5">
                </ArcSegment>
            </PathFigure>
        </PathGeometry>
    </Path.Data>
    <Path.Stroke>
        <LinearGradientBrush StartPoint="0, 0.5" EndPoint="1, 0.5">
            <GradientStop Offset="0" Color="Green" />
            <GradientStop Offset="0.5" Color="Red" />
            <GradientStop Offset="1.0" Color="Yellow"/>
        </LinearGradientBrush>
    </Path.Stroke>
</Path>

Или в другом направлении:

<Path.Stroke>
    <LinearGradientBrush StartPoint="0.5, 0" EndPoint="0.5, 1">
        <GradientStop Offset="0" Color="Green" />
        <GradientStop Offset="0.5" Color="Red" />
        <GradientStop Offset="1.0" Color="Yellow"/>
    </LinearGradientBrush>
</Path.Stroke>

Но проблема в том, что градиент используется для всей поверхности, и поэтому я нарисовал красным два вместо одного раза и не правильно в начале цикла:

Look with Solid gradient

Я пытаюсь использовать кисть с изображением, имеющим градиент, как я хочу.

<Path.Stroke>
    <ImageBrush ImageSource="../brush.png"  />
</Path.Stroke>

Это прекрасно работает для значений> 75%, но длянижние значения также нарисована зеленая часть, что не должно быть.

enter image description here

Любой идеал, что я могу сделать, чтобы сделать эту работу?

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

Я работаю с ImageBrush.Рекомендуется использовать только ту часть изображения, которая необходима для рисования путем обрезки.

Для этого я использовал конвертер, который возвращает ImageBrush для текущего процентного значения.

public class ValueToImageBrush : IValueConverter
{
    private const string _filePath = "pack://application:,,,/XXX;component/brush.png";
    private BitmapImage _baseImage;

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var doubleValue = value as double?;
        if (doubleValue == null) return new SolidColorBrush(Colors.LightSlateGray);

        var baseImg = LoadImage();           
        var img = CutImage(baseImg, doubleValue.Value);

        return InitImageBrush(img);
    }       


    private BitmapImage LoadImage()
    {
        if (_baseImage == null)
        {
            _baseImage = new BitmapImage();
            _baseImage.BeginInit();
            _baseImage.UriSource = new Uri(_filePath);
            _baseImage.EndInit();
        }
        return _baseImage;
    }

    private static ImageSource CutImage(BitmapImage baseImg, double doubleValue)
    {
        var img = baseImg as ImageSource;
        if (doubleValue < 50)
        {
            var usedHight = Math.Max(25.0, baseImg.PixelHeight * (doubleValue * 2 / 100));
            img = new CroppedBitmap(baseImg,
                new Int32Rect(baseImg.PixelWidth / 2, 0, baseImg.PixelWidth / 2, (int)usedHight));
        }
        else if (doubleValue < 75)
        {
            var usedWidth = baseImg.PixelWidth * (doubleValue / 100);
            img = new CroppedBitmap(baseImg, new Int32Rect(200 - (int)usedWidth, 0, (int)usedWidth, baseImg.PixelHeight));
        }

        return img;
    }
    private static object InitImageBrush(ImageSource img)
    {
        ImageBrush imgBrush = new ImageBrush();
        imgBrush.ImageSource = img;
        imgBrush.Stretch = Stretch.None;
        return imgBrush;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Я не уверен, что это самое умное решение, но оно работает быстро и не очень сложно для реализации.Может быть, у кого-то есть лучшее решение.

0 голосов
/ 24 октября 2018

Я не думаю, что такой вид отображения возможен при использовании кисти с линейным градиентом.

Мое решение состояло бы в том, чтобы разделить элемент управления на несколько небольших клинообразных элементов, каждый из которых имеетодин сплошной цвет.Цвет каждого элемента рассчитывается на основе его угла и начального / конечного угла элемента управления (если вы собираетесь прилагать усилия для создания такого элемента управления, вы могли бы также сделать его немного более универсальным) и требуемойцвет останавливается.

Вы не можете просто использовать цветовое пространство Red / Green / Blue и интерполировать цвет для отдельного элемента - вам придется использовать что-то вроде Hue / Saturation / Luminosity вместо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...