vannut / statamic-weather-addon

🎏 A Statamic-Addon for the OpenWeathermap API
5 stars 0 forks source link

Units Conversion Modifier #7

Open Wibbmer opened 2 years ago

Wibbmer commented 2 years ago

I've tinkered around a little and created a modifier for the {{ wind_speed }} field. This replaces the need i.e. for a custom {{speed_bft}} field.

Now you can convert to speed units on the fly like so:

{{ wind_speed | unit:{unit} }}

replace {unit} with one of the following to convert or remove the modifier for default units

for metric units (no ms since it's the default)

for imperial units (no mph since it's the default)

To register it in ServiceProvider.php just add

use Vannut\StatamicWeather\Modifiers\ConvertSpeedToUnitModifier;

protected $modifiers = [
        ConvertSpeedToUnitModifier::class,
    ];

And for the modifier itself create the file src\Modifiers\ConvertSpeedToUnitModifier.php

<?php

namespace Vannut\StatamicWeather\Modifiers;

use Statamic\Modifiers\Modifier;
use Vannut\StatamicWeather\Settings;

class ConvertSpeedToUnitModifier extends Modifier
{
    protected static $handle = 'unit';

    public function index($value, $params, $context)
    {
        // Get the default units set in the control panel from which to convert
        $config = (new Settings)->get();
        $currentUnits = $config->get('units','metric');
        $targetUnits = '';
        $result;

        if ($param = array_get($params, 0)) {
            // Either get the variable from the context, or if it doesn't exist,
            // use the parameter itself - we'll assume its a number.
            $targetUnits = array_get($context, $param, $param);
        }

        if($currentUnits == 'metric')
        {
            if($targetUnits=='kmh')
            {
                $result=round($value*3.6,2);
            }
            elseif ($targetUnits=='mph'){
                $result=round($value*2.237,2);
            }
            elseif($targetUnits=='bft')
            {
                if ($value < 0.3)
                {
                    return 0;
                } else if ($value < 1.6)
                {
                    return 1;
                } else if ($value < 3.4)
                {
                    return 2;
                } else if ($value < 5.5)
                {
                    return 3;
                } else if ($value < 8)
                {
                    return 4;
                } else if ($value < 10.8)
                {
                    return 5;
                } else if ($value < 13.9)
                {
                    return 6;
                } else if ($value < 17.2)
                {
                    return 7;
                } else if ($value < 20.8)
                {
                    return 8;
                } else if ($value < 24.5)
                {
                    return 9;
                } else if ($value < 28.5)
                {
                    return 10;
                } else if ($value < 32.6)
                {
                    return 11;
                } else
                {
                    return 12;
                }
            }
        }
        else {
            if($targetUnits=='kmh')
            {
                $result=round($value*1.609,2);
            }
            elseif ($targetUnits=='ms'){
                $result=round($value/2.237,2);
            }
            elseif($targetUnits=='bft')
            {
                if ($value < 1)
                {
                    return 0;
                } else if ($value < 4)
                {
                    return 1;
                } else if ($value < 8)
                {
                    return 2;
                } else if ($value < 13)
                {
                    return 3;
                } else if ($value < 19)
                {
                    return 4;
                } else if ($value < 25)
                {
                    return 5;
                } else if ($value < 32)
                {
                    return 6;
                } else if ($value < 39)
                {
                    return 7;
                } else if ($value < 47)
                {
                    return 8;
                } else if ($value < 54)
                {
                    return 9;
                } else if ($value < 64)
                {
                    return 10;
                } else if ($value < 73)
                {
                    return 11;
                } else
                {
                    return 12;
                }
            }
        }

        return $result;
    }
}

It's nothing too fancy, but it works :)

vannut commented 2 years ago

This is actually a good idea! But I also see some duplication in these functions and the ConversionTrait. Ideally I want to reuse this logic.

Wibbmer commented 2 years ago

The modifier now uses the ConversionTrait


<?php

namespace Vannut\StatamicWeather\Modifiers;

use Statamic\Modifiers\Modifier;
use Vannut\StatamicWeather\ConversionTrait;
use Vannut\StatamicWeather\Settings;

class ConvertSpeedToUnitModifier extends Modifier {

    use ConversionTrait;

    protected static $handle = 'unit';

    public function index($value, $params, $context)
    {
        // Get the default units set in the control panel from which to convert
        $config = (new Settings)->get();
        $currentUnits = $config->get('units', 'metric');
        $targetUnits;

        if ($param = array_get($params, 0))
        {
            // Either get the variable from the context, or if it doesn't exist,
            // use the parameter itself - we'll assume its a number.
            $targetUnits = array_get($context, $param, $param);
        }

        return $this->speedToUnit($value, $currentUnits, $targetUnits);
    }
}

The new function in ConversionTrait


 /**
     * Converts speed from default speed units to selected
     *
     * @param float $speed The current wind speed either in ms or mph
     * @param string $measurement Metric/Imperial
     * @param string $to The desired speed unit
     *
     * @return $convertedSpeed
     */

    private function speedToUnit($speed, $measurement, $to)
    {
        if ($measurement == 'metric')
        {
            switch ($to)
            {
                case 'kmh':
                    $convertedSpeed = round($speed * 3.6, 2);
                    break;
                case 'mph':
                    $convertedSpeed = round($speed * 2.237, 2);
                    break;
                case 'bft':
                    $convertedSpeed = $this->msToBft($speed);
                    break;
                case 'ms':
                    $convertedSpeed = $speed;
                    break;
            }
        } else
        {
            switch ($to)
            {
                case 'kmh':
                    $convertedSpeed = round($speed * 1.609, 2);
                    break;
                case 'ms':
                    $convertedSpeed = round($speed / 2.237, 2);
                    break;
                case 'bft':
                    $convertedSpeed = $this->mphToBft($speed);
                    break;
                case 'mph':
                    $convertedSpeed = $speed;
                    break;
            }
        }

        return $convertedSpeed;
    }

I've left in ms and mph even though they are redundant to avoid accidental breakage when changing units but not updating the modifier in antlers.

Wibbmer commented 2 years ago

I've created separate functions for each speed unit now, to DRY up the two switch statements. I'm not quite sure about it, so let me know what you think. The modifier stays untouched by this.

In ConversionTrait.php


    private function speedToUnit($speed, $measurement, $to)
    {
        switch ($to)
        {
            case 'kmh':
                $convertedSpeed = $this->speedToKmh($speed,$measurement);
                break;
            case 'mph':
                $convertedSpeed = $this->speedToMph($speed,$measurement);
                break;
            case 'bft':
                $convertedSpeed = $this->speedToBft($speed,$measurement);
                break;
            case 'ms':
                $convertedSpeed = $this->speedtToMs($speed,$measurement);
                break;
        }

        return $convertedSpeed;
    }

    private function speedtToMs($speed, $measurement)
    {
        if ($measurement == 'metric')
        {
            return $speed;
        } else
        {
            return round($speed / 2.237, 2);
        }
    }

    private function speedToMph($speed, $measurement)
    {
        if ($measurement == 'metric')
        {
            return round($speed * 2.237, 2);
        } else
        {
            return $speed;
        }
    }

    private function speedToKmh($speed, $measurement)
    {
        if ($measurement == 'metric')
        {
            return round($speed * 3.6, 2);
        } else
        {
            return round($speed * 1.609, 2);
        }
    }

    private function speedToBft($speed, $measurement)
    {
        if ($measurement == 'metric')
        {
            return $this->msToBft($speed);
        } else
        {
            return $this->mphToBft($speed);
        }
    }