Tube Map Uses in Android application

Hi All,

I am developing an application for android devices. There is a functionality to show the London tube map. There I wanted to show the London Tub Map (see below-mentioned URL).

http://content.tfl.gov.uk/standard-tube-map.pdf

Please let me know can I use this map in the application, does it violating any policy to use in the application.

Or suggest, is there any free map that can be used in the application for the free application.

Thank you.

@pdev

Please see this link for the general advice

If you LINK to “http://content.tfl.gov.uk/standard-tube-map.pdf” above in your app, that’s OK: the PDF contains the copyright notice.

However, you might have problems if you create a thumbnail or cache the PDF in your app.

Thank you Braintist for the information, Yes I have seen the Map licensing is very expensive to use in the application. It cost the royalty-free price for internet usage is £320 + VAT (as per website) for Tube map. As an individual hobbyist software developer it is costly :slight_smile:

If you have any suggestion or alternative of using any free map kindly share.

Does TFL API provide any map functionality for the developer?

Otherwise, I believe that I have to remove the “Map View” functionality in my application. :frowning:

Thank you for your help.

1 Like

I have a few “work-arounds” that I have used myself.

Firstly, you can use the http://content.tfl.gov.uk/tfl-line-diagram-standard.pdf document to generate your own on-the-fly diagrams. I wrote some code to make SVG diagrams that could show ad-hoc lines.

http://tubedreams.freeview.tv/wp-content/uploads/2015/02/pica.svg

The other way to do diagrams is using the Wikipedia diagram generator… Everything is in the public domain (in German, however)…

Hi Braintist,

Thank for the workaround solution. Let me analyse, how I can utilize this solution in my application. Primarily in the application “Map View” functionality suppose to show the full map of London Underground for the pictorial representation of the all the stations with respective lines on the map. Secondly, it will be having an option in the “Plan Journey” functionality where one can plan their journey and result will show a path line to the user (w.r.t. source and destination entered by the user and result will show stations and junctions to reach the respective destination). There I will highlight result path on the map so the user will easily understand the path route on the map to move on.

If you don’t mind can you please share the code that you have written for the making SVG diagram.

Thank you again for your help.

@pdev

OK, I have unpicked my SVG-generating code so that I can post it here in a way that works. The calls to the SVG generation uses a config array so that you can put in the necessary stations or whatever. There are lots of types such as NORMAL, INTERSECTION, ENDPOINT, CURVE, BACKCURVE, WALKTO, DOTTED, DOTTEDLEFT, DOTTEDRIGHT.

Note in the code you can set the line colour by line name. It will auto-fix the correct type of line (1/3+1/3+1/3 or solid line).

namespace view\lineDiagramSimple;

use view\helper\html;

class testSVG
{
    const BIGSIZE = 43;

    public function __construct()
    {
        $harryBeckLineDiagramExtended = new HarryBeckLineDiagramExtended();
        $harryBeckLineDiagramExtended->setHeight(330);
        $intSpacing = self::BIGSIZE;
        $arrPlaces[] = [
            tube::LINE => "Pink",
            tube::TITLE => "STAR line",
            tube::NODES => [
                "Stratford" => [
                    tube::TYPE => tube::INTERSECTION,
                    tube::TERMINATES => true
                ],
                "Lea Bridge" => [
                    tube::TYPE => "normal"
                ],
                "Tottenham Hale" => [
                    tube::TYPE => tube::INTERSECTION,
                    tube::NATIONAL => true
                ],
                "Northumberland Park" => [
                    tube::TYPE => "normal"
                ], "Angel Road" => [
                    tube::TYPE => tube::ENDPOINT,
                    tube::NATIONAL => true
                ]
            ]
        ];
        foreach ($arrPlaces as $arrPlace) {
            $harryBeckLineDiagramExtended->newPlaces($arrPlace);
            $harryBeckLineDiagramExtended->overrideLineColour("Overground");
            $harryBeckLineDiagramExtended->setWidth(100 + $intSpacing * 4 * pre72::count($arrPlace));
        }
        $strEcho = $harryBeckLineDiagramExtended->createOutput() . html::pGap();
        echo($strEcho);
    }
}

Will make

image

<?php


namespace view\lineDiagramSimple;


class HarryBeckLineDiagramExtended extends HarryBeckLineDiagram
{

    public $arrAccess = ["Shenfield" => "W", "Brentwood" => "W", "Romford" => "W", "Chadwell Heath" => "W", "Stratford" => "W", "Liverpool Street" => "W",
        "Heathrow T5" => "B", "Hearthrow T23" => "B", "Paddington" => "W", "Heathrow Airport T123" => "B", "Heathrow Airport T5" => "B"];


//    public function __toString()
//    {
//        return $this->createOutput();
//    }


    /*
     *
     *       So, need to convert the arrays to objects
     *
     */
    public $ynShowTitleInSVG = true;

    public function createOutput()
    {
        $this->setSwap($this->ynRotated);

        $intLeft = $this->intBorder;
        $intRight = $this->intWidth - $this->intBorder;
        $intMiddle = $this->intHeight / 2;
        $intLeftXtra = $intLeft;
        $intRightXtra = $intRight;
        $strLineColour = $this->strLineColour;
        if (isset($this->arrPlaces[Tube::DOTCOLOUR])) {
            $this->setDottedColour($this->arrPlaces[Tube::DOTCOLOUR]);
        }
        if (count($this->arrPlaces[Tube::NODES]) > 0) {
            if (count($this->arrPlaces[Tube::NODES]) > 1) {
                $intXincrement = ($intRight - $intLeft) / (count($this->arrPlaces[Tube::NODES]) - 1);
                $this->intHozintalTextIncremaent = $this->intBorder / 2;
            } else {
                $intXincrement = ($intRight - $intLeft);
            }
            if (isset($this->arrPlaces[Tube::REVERSE])) {
                if ($this->arrPlaces[Tube::REVERSE] === true) {
                    $this->arrPlaces[Tube::NODES] = array_reverse($this->arrPlaces[Tube::NODES]);
                }
            }
            $this->preparations($intLeftXtra, $intRightXtra, $strLineColour);
            $this->splitLineConfig($intLeftXtra, $intMiddle, $intRightXtra, $strLineColour);
            $intXthis = $intLeft;
            $intCounter = 0;


            foreach ($this->arrPlaces[Tube::NODES] as $strPlacename => $arrConfig) {
                if (isset($this->arrAccess[$strPlacename])) {
                    $arrConfig["type"] = "access" . $this->arrAccess[$strPlacename];
                }
                if (isset($arrConfig[Tube::MECODE])) {
                    $fpPlaceAlong = $intCounter;
                }
                $this->mainDrawingLoop($arrConfig, $intMiddle, $strPlacename, $intXincrement, $intXthis, $strLineColour, $intCounter);
            }
        }





        if (!$this->ynRotated) {
            if ($this->ynShowTitleInSVG) {
                $this->addText($this->arrPlaces[Tube::TITLE], 0, 20, 20, "left", "Indigo", 500);
            }
            return $this->htmlimageinsert($this->intWidth, $this->intHeight, $this->strEmailMode);
        } else {
            if ($this->ynShowTitleInSVG) {
                $this->addText($this->arrPlaces[Tube::TITLE], 20, 0, 20, "left", "Indigo", 500);
            }
            return $this->htmlimageinsert($this->intHeight, $this->intWidth, $this->strEmailMode);
        }
    }

    public function mainDrawingLoop($arrConfig, &$intMiddle, &$strPlacename, &$intXincrement, &$intXthis, &$strLineColour, &$intCounter)
    {
        $intThisY = $intMiddle - $this->intGrid;

        if ($arrConfig[Tube::TYPECODE] === Tube::CURVE or $arrConfig[Tube::TYPECODE] === Tube::BACKCURVE) {
            $intThisY -= $this->intGrid / 2;
            if ($arrConfig[Tube::TYPECODE] === Tube::CURVE)
                $strPlacename = ".. " . $strPlacename;
            if ($arrConfig[Tube::TYPECODE] === Tube::BACKCURVE)
                $strPlacename = ".. " . $strPlacename;
        }
        $this->startAhref("http://eventadmin/filesystem/templates");
        $strPlacename2 = $strPlacename;
        $intTextMaxSize = $intXincrement;
        if ($this->ynRotated) {
            $intTextMaxSize = $intMiddle;
        }
        $strPlacename2 = $this->autoFixNewLines($strPlacename2, $intTextMaxSize - 4, ScalableVectorGraphics::FONTSIZEBIG);
        if (isset($arrConfig[Tube::NATIONAL])) {
            if ($arrConfig[Tube::NATIONAL]) {
                $strPlacename2 = strtr("NR\n" . $strPlacename2, [
                    "\n\n" => "\n"
                ]);
            }
        }
        if (isset($arrConfig[Tube::WALKING])) {
            if ($arrConfig[Tube::WALKING]) {
                $strPlacename2 = strtr("WALK\n" . $strPlacename2, [
                    "\n\n" => "\n"
                ]);
            }
        }
        $strTextDecor = "";
        if (isset($arrConfig[Tube::STRIKEOUT])) {
            if ($arrConfig[Tube::STRIKEOUT] === true) {
                $strTextDecor = "line-through";
//                $strPlacename2.=" ---";
            }
        }

        if (!isset($arrConfig[Tube::MECODE])) {
            $arrConfig[Tube::MECODE] = false;
        }


        if (!$this->ynRotated) {
            $intXXmore = 10 - 3;
            /*
             *   This is HORIZONTAL MODE
             *
             */
            $this->addTheStationName($strPlacename2, $intXthis, $intMiddle * .5, $intXXmore, $arrConfig[Tube::MECODE], $strTextDecor, "middle");

        } else {


            /*
            *   This is VERTICAL MODE
            *
            */

//            if ($arrConfig[Tube::TYPECODE] === Tube::CURVE or $arrConfig[Tube::TYPECODE] === Tube::BACKCURVE) {
//                $intXXmore = -$this->intGrid / 1 + 10;
//            } else {
//                $intXXmore = -40;
//            }

//            $this->addTheStationName("0", $intXthis, 50    , 0, $arrConfig[Tube::MECODE], $strTextDecor);
            $this->addTheStationName($strPlacename2, $intXthis, 50, 0, $arrConfig[Tube::MECODE], $strTextDecor, "middle");


        }
        $this->endAhref();
        switch ($arrConfig[Tube::TYPECODE]) {
            case Tube::CURVE:
                $intXof = $this->intGrid;
                $this->addBezierCurveQuadratic($intXthis - $intXof, $intMiddle, $intXthis, $intMiddle - $intXof, $strLineColour, self::LINEWIDTH, "round");
                break;
            case Tube::BACKCURVE:
                $intXof = $this->intGrid;
                $this->addBezierCurveQuadratic($intXthis + $intXof, $intMiddle, $intXthis, $intMiddle - $intXof, $strLineColour, self::LINEWIDTH, "round");
                break;
            case Tube::ENDPOINT:
                $this->addLine($intXthis, $intMiddle + $this->intGrid / 1.5, $intXthis, $intThisY + $this->intGrid / 3, $strLineColour, self::LINEWIDTH, "butt");
                break;
            case Tube::DOTTED:
                break;
            case Tube::BLANK:
                break;
            case "accessW":
            case "accessB":
            case Tube::INTERSECTION:
                $this->createIntersection($intXthis, $intMiddle, $strPlacename, $arrConfig, $arrConfig[Tube::TYPECODE]);
                break;
            default:
                $this->addLine($intXthis, $intMiddle - 3, $intXthis, $intThisY + $this->intGrid / 1.66, $strLineColour, self::LINEWIDTH * .66, "butt");
        }
        $intXmore = 0;
        $intYmore = 0;
        if ($this->ynRotated) {
            if (!isset($arrConfig[Tube::INTERSECTION])) {
                $arrConfig[Tube::INTERSECTION] = [];
            }
            $intXmore = self::FONTSIZENORMAL * 3 - self::FONTSIZENORMAL / 1.5 * pre72::count($arrConfig[Tube::INTERSECTION]);
        }
        if (isset($arrConfig[Tube::INTERSECTION])) {
            if (count($arrConfig[Tube::INTERSECTION]) > 0) {
                foreach ($arrConfig[Tube::INTERSECTION] as $strLine) {
                    $this->addLineSymbol($strLine, $intXthis + $intXmore, $intMiddle + $intYmore);
                    if (!$this->ynRotated) {
                        $intYmore += self::FONTSIZENORMAL * .8 * 2;
                    } else {
                        $intXmore += self::FONTSIZENORMAL * .8 * 2;
                    }
                }
                if (!$this->ynRotated) {
                    $intYmore += self::FONTSIZENORMAL;
                } else {
                    $intXmore += self::FONTSIZENORMAL;
                    $intXmore -= 35;
                }
            } else {
                $intXmore = 0;
            }
        }
        if (isset($arrConfig[Tube::MORETEXT])) {
            if ($arrConfig[Tube::MORETEXT] != "") {
                $strText = $this->autoFixNewLines($arrConfig[Tube::MORETEXT], $intTextMaxSize, self::FONTSIZENORMAL);
                $strText = strtr($strText, [
                    "\n\n" => "\n"
                ]);
                if (!$this->ynRotated) {
                    $this->addText($strText, $intXthis, $intMiddle + $intYmore + $this->intGrid * 1.2, self::FONTSIZENORMAL, $this->getAlignFor(), "Black", 500, false);
                } else {
                    $this->addText($strText, $intXthis + $intXmore, $intMiddle + $this->intGrid * 2, self::FONTSIZENORMAL, $this->getAlignFor(), "Black", 500, false);
                }
            }
        }
        $intXthis += $intXincrement;
        $intCounter += 1;
    }


}

<?php


namespace view\lineDiagramSimple;


class HarryBeckLineDiagram extends TrainProgressSVG
{
    const FONTSIZENORMAL = 11;
    const LINEWIDTH = 11;
    const COACHWIDTH = 20;
    const COACHHEIGHT = 16;
    const LOADINGXOFSET = 10;
    const LOADINGYOFSET = 120;
    const ARRTRANSLATE = [
        "VIC_" => "Victoria",
        "OVE_" => "Overground",
        "CEN_" => "Central",
        "JUB_" => "Jubilee",
        "DLR_" => "DLR",
        "XR1_" => "TfLRail",
        "NTN_" => "Northern",
        "BAK_" => "Bakerloo",
        "DIS_" => "District",
        "CIR_" => "Circle",
        "MET_" => "Metropolitan",
        "PIC_" => "Picadilly",
        "HAM_" => "H'smith+City",
        "WAC_" => "Waterloo+City"
    ];
    public $strThisLineName = "";
    public $arrPlaces = [];
    public $intWidth = 1200;
    public $intHeight = 450;
    public $intBorder = 60;
    public $intGrid = 32;
    public $tube;
    public $ynRotated = false;
    public $strDottedColour = "LightGrey";
    public $strEmailMode = "html";
    public $strLineColour = "";
    public $ynIsThirdWhite = true;
    public $intHozintalTextIncremaent = 0;

    public function __construct()
    {
        parent::__construct();
        $this->tube = new Tube();
    }



    public function setWidth($intWidth = 1200)
    {
        $this->intWidth = $intWidth;
    }

    public function setHeight($intHeight = 450)
    {
        $this->intHeight = $intHeight;
    }


    public function newPlaces($arrPlaces, $ynRotated = false)
    {
        $this->arrPlaces = $arrPlaces;
        $this->ynRotated = $ynRotated;
    }

    public function overrideLineColour($strLineColour, $ynIsThirdWhite = false)
    {
        $this->strLineColour = $strLineColour;
        $this->ynIsThirdWhite = $ynIsThirdWhite;
    }

    public function setDottedColour($strColour)
    {
        $this->strDottedColour = $strColour;
    }

    public function preparations(&$intLeftXtra, &$intRightXtra, &$strLineColour)
    {
        $intCounter = 0;
        $intCountPlaces = pre72::count($this->arrPlaces[Tube::NODES]);
        foreach ($this->arrPlaces[Tube::NODES] as $strPlacename => $arrConfig) {
            foreach ([Tube::TYPECODE, Tube::TERMINATES, Tube::NATIONAL, Tube::STRIKEOUT, Tube::MORETEXT, Tube::WALKM, Tube::FORCE, Tube::FALLBACK] as $strFix) {
                if (!isset($arrConfig[$strFix])) {
                    $arrConfig[$strFix] = null;
                }
            }
            if (!isset($arrConfig[Tube::INTERSECTION])) {
                $arrConfig[Tube::INTERSECTION] = [];
            }
            if ($intCounter == 0 and ($arrConfig[Tube::TYPECODE] != Tube::ENDPOINT and $arrConfig[Tube::TYPECODE] != Tube::ARROW and $arrConfig[Tube::TERMINATES] != true)) {
                $intLeftXtra -= $this->intGrid;
            }
            if ($intCounter == pre72::count($this->arrPlaces[Tube::NODES]) - 1 and ($arrConfig[Tube::TYPECODE] != Tube::ENDPOINT and $arrConfig[Tube::TYPECODE] != Tube::ARROW and $arrConfig[Tube::TERMINATES] != true)) {
                $intRightXtra += $this->intGrid;
            }
            if ($arrConfig[Tube::TYPECODE] == Tube::DOTTED) {
                $this->arrPlaces[Tube::COLOURSPLIT][$intCounter] = Tube::DOTTEDRIGHT;
                if ($intCounter >= 1) {
                    $this->arrPlaces[Tube::COLOURSPLIT][$intCounter - 1] = Tube::DOTTEDLEFT;
                }
            } else {
                if (isset($this->arrPlaces[Tube::COLOURSPLIT][$intCounter])) {
                    if ($this->arrPlaces[Tube::COLOURSPLIT][$intCounter] == "" and $intCounter < $intCountPlaces - 1) {
                        $this->arrPlaces[Tube::COLOURSPLIT][$intCounter] = $strLineColour;
                    }
                }
            }
            $intCounter += 1;;
        }
    }

    public function splitLineConfig($intLeftXtra, $intMiddle, $intRightXtra, $strLineColour)
    {
        if (isset($this->arrPlaces[Tube::COLOURSPLIT])) {
            $intSplitCount = pre72::count($this->arrPlaces[Tube::COLOURSPLIT]);
        } else {
            $intSplitCount = 0;
        }
        if ($intSplitCount == 0) {
            $this->addLine($intLeftXtra, $intMiddle, $intRightXtra, $intMiddle, $strLineColour, self::LINEWIDTH);
        } else {
            $fpWidthDiv = ($intRightXtra - $intLeftXtra) / $intSplitCount;
            $fpHolder = $intLeftXtra;
            $strLastColour = $strLineColour;
            foreach ($this->arrPlaces[Tube::COLOURSPLIT] as $intCounter => $strLineColourLocal) {
                switch ($strLineColourLocal) {
                    case Tube::DOTTEDLEFT:
                        $strLastColour = $this->strDottedColour;
                        $this->addLine($fpHolder, $intMiddle, $fpHolder + $fpWidthDiv * .5, $intMiddle, $strLastColour, self::LINEWIDTH);
//                        $this->addLineOfDots($fpHolder + $fpWidthDiv * .5, $intMiddle, $fpHolder + $fpWidthDiv * 1.5, $intMiddle, $strLastColour, self::LINEWIDTH, 5, 20);
                        $this->addLineOfDots($fpHolder + $fpWidthDiv * .5, $intMiddle, $fpHolder + $fpWidthDiv * 1.5, $strLastColour, self::LINEWIDTH); //, 5, 20);
                        break;
                    case Tube::DOTTEDRIGHT:
                        $this->addLine($fpHolder + $fpWidthDiv * .5, $intMiddle, $fpHolder + $fpWidthDiv, $intMiddle, $strLastColour, self::LINEWIDTH);
                        break;
                    default:
                        $this->addLine($fpHolder, $intMiddle, $fpHolder + $fpWidthDiv, $intMiddle, $strLineColourLocal, self::LINEWIDTH);
                        $strLastColour = $strLineColourLocal;
                        break;
                }
                $fpHolder += $fpWidthDiv;
            }
        }
        if ($this->ynIsThirdWhite) {
            $this->addLine($intLeftXtra, $intMiddle, $intRightXtra, $intMiddle, "#ffffff", self::LINEWIDTH * .333);
        }
    }

    public function autoFixNewLines($strPlacename, $intMaxWidth, $intSizePX = ScalableVectorGraphics::FONTSIZEBIG)
    {
        $arrPlacenameBits = preg_split("/ /", $strPlacename);
        $intRowOut = 0;
        $arrOutBits = [
            $intRowOut => ""
        ];
        foreach ($arrPlacenameBits as $strWord) {
            if (self::getTextWidth($arrOutBits[$intRowOut] . " " . $strWord, $intSizePX) > $intMaxWidth) {
                $intRowOut += 1;
                $arrOutBits[$intRowOut] = $strWord;
            } else {
                $arrOutBits[$intRowOut] .= " " . $strWord;
            }
        }
        return strtr(join("\n", $arrOutBits), [
            "\n\n" => "\n"
        ]);
    }

    public function addTheStationName($strPlacename2, $intXthis, $intMiddle, $intXXmore, $ynIsMe, $ynCrossedOut, $strAlign)
    {
        /*
         *
         *   Assume NOT rotated
         *
         */
        $strTextColor = "Pidcadilly";
        $intXXmore = $intXXmore + 30;

        if ($ynIsMe and !$this->ynRotated) {

            $arrBounds = self::calculateTextBoundingBox($strPlacename2, $intXXmore, $intXthis, $intMiddle);
            if ($intXXmore !== 30) {
                $arrBounds["y"] += 40;
            } else {
//                $arrBounds["x"]+=40;
                $arrBounds["y"] = 0;
                $arrBounds["w"] = 140;
                $arrBounds["x"] += 40;
                $arrBounds["h"] = 60;
            }


            $this->addRectangle($arrBounds["x"], $arrBounds["y"], $arrBounds["w"], $arrBounds["h"], "Pidcailly", "Pidcailly");
            $strTextColor = "White";
        }

        $this->addText($strPlacename2, $intXthis, $intMiddle + $intXXmore, ScalableVectorGraphics::FONTSIZEBIG, $strAlign, $strTextColor);


        if ($ynCrossedOut != "") {

            $arrBounds = self::calculateTextBoundingBox($strPlacename2, $intXXmore, $intXthis, $intMiddle);

            if (!$this->ynRotated) {
                $ycorrection = 40;
            } else {
                $ycorrection = 0;
            }


            $this->addLine($arrBounds["x"], $arrBounds["y"] + $ycorrection, $arrBounds["x"] + $arrBounds["w"], $arrBounds["y"] + $arrBounds["h"] + $ycorrection, "rgba(220, 36, 31, 1)", 2);


        }
        return;
    }

    public function showTrainLoadingIndicator($intXthis, $intMiddle, $intCarriges = 5)
    {
        for ($intI = 0; $intI < $intCarriges; $intI += 1) {
            $fpLoad = rand(0, 100) / 100;
            $this->addRectangle($intXthis + self::LOADINGXOFSET, $intMiddle + self::LOADINGYOFSET + $intI * self::COACHWIDTH, self::COACHWIDTH - 2, self::COACHHEIGHT, "#F6BF28", "#E27F27");
            $this->addRectangle($intXthis + self::LOADINGXOFSET, $intMiddle + self::LOADINGYOFSET + $intI * self::COACHWIDTH, self::COACHWIDTH - 2, self::COACHHEIGHT * $fpLoad, "#1C4692", "#1C4692");
        }
    }

    public function createIntersection($intXthis, $intMiddle, $strPlacename, &$arrConfig, $strType = "")
    {
        switch ($strType) {
            case "accessW":
                $this->addCircle($intXthis, $intMiddle, self::LINEWIDTH * 1.5, "#0450a1");
                $this->addCircle($intXthis, $intMiddle, self::LINEWIDTH * 1.3, "White");  ///White is correct
                $this->accessLogo($intXthis, $intMiddle);
                break;
            case "accessB":
                $this->addCircle($intXthis, $intMiddle, self::LINEWIDTH * 1.5, "#0450a1");
//                $this->addCircle($intXthis, $intMiddle, self::LINEWIDTH * 1.3, "White");
                $this->accessLogo($intXthis, $intMiddle, "fill:#ffffff;fill-rule:nonzero");
                break;
            default:
                $this->addCircle($intXthis, $intMiddle, self::LINEWIDTH * 1.5, "#000000");
                $this->addCircle($intXthis, $intMiddle, self::LINEWIDTH * 1, "White");
                break;
        }
        $strPlacename2 = $strPlacename;
        if (isset($arrConfig[Tube::WALKTO])) {
            if ($arrConfig[Tube::WALKTO] != "") {
                $strPlacename2 = $arrConfig[Tube::WALKTO];
                if (true) {
                    $arrConfig[Tube::MORETEXT] .= $strPlacename2 . " " . $arrConfig[Tube::WALKM] . "m";
                }
            }
        }
        if (isset($arrConfig[Tube::FORCE])) {
            if ($arrConfig[Tube::FORCE] === true) {
                $this->strThisLineName = "";
            }
        }
        if (!isset($arrConfig[Tube::FALLBACK])) {
            $arrConfig[Tube::FALLBACK] = [];
        }
        $arrConfig[Tube::INTERSECTION] = $this->intersectional($strPlacename2, $this->strThisLineName, $arrConfig[Tube::FALLBACK]);
        if (!isset($arrConfig[Tube::FORCE])) {
            $arrConfig[Tube::FORCE] = false;
        }
        if (count($arrConfig[Tube::INTERSECTION]) == 0 and $arrConfig[Tube::FORCE] === true) {
            $arrConfig[Tube::INTERSECTION] = [
                $this->arrPlaces[Tube::LINECODE] => $this->arrPlaces[Tube::LINECODE]
            ];
        }
        if (isset($arrConfig[Tube::TRAMCODE])) {
            if ($arrConfig[Tube::TRAMCODE] == true) {
                $arrConfig[Tube::INTERSECTION]["Tramlink"] = "Tramlink";
            }
        }
    }

    public function intersectional($strPlacename, $strLineIDexclude = "Overground", $arrFallback = [])
    {
        $strPlacename = Tube::cleanName(strtr($strPlacename, ["\n" => " "]));
        $arrTranslate = self::ARRTRANSLATE;
        $arrCollection = $arrFallback;
        {
            foreach ($this->tube->arrLineData as $strFilename => $arrLine) {
                $arrBitz = preg_split("/-/", $strFilename);
                $strLineID = strtr($arrBitz[1], $arrTranslate);
                foreach ($arrLine as $strPath) {
                    $strCP = Tube::cleanName($strPath);
                    $strCP = strtr($strCP, [
                        " & " => " and "
                    ]);
                    if ($strCP == $strPlacename and $strLineID != $strLineIDexclude) {
                        $arrCollection[$strLineID] = $strLineID;
                    }
                }
            }
        }
        return $arrCollection;
    }

    public function addLineSymbol($strLine, $intXthis, $intMiddle)
    {
        $intH = self::FONTSIZENORMAL * .8;
        $inthofset = 4;
        $intyofset = 0;
        if ($this->ynRotated) {
            $inthofset = 30;
            $intyofset = -26;;
        }
        $intW = 80;
        $intMiddle = $intMiddle + $this->intGrid * 1.2;
        if ($this->addRectangle($intXthis - $intW / 2, $intMiddle - $intH, $intW, $intH * 2, $strLine, "#000000", 0.5) != "#ffffff") {
            $strTextColour = "White";
        } else {
            $strTextColour = "Black";
        }
        $this->addText(($strLine), $intXthis + $intyofset, $intMiddle + $inthofset, self::FONTSIZENORMAL, "middle", $strTextColour, 500, false);
    }

    public function getAlignFor()
    {
        if ($this->ynRotated) {
            return "middle";
        } else {
            return "middle";
        }
    }
}

<?php


namespace view\lineDiagramSimple;




class TrainProgressSVG extends SvgForHtml
{
    const NRLOGO = "M 926.28993,538.90218 L 748.40295,459.541 L 1000,459.541 L 1000,406.46975 L 741.03194,406.46975 L 872.72727,342.83339 L 1000,342.83339 L 1000,291.72774 L 872.72727,291.72774 L 712.28501,217.52626 L 590.17199,217.52626 L 759.95086,291.72774 L 500,291.72774 L 500,342.83339 L 759.95086,342.83339 L 624.07862,406.46975 L 500,406.46975 L 500,459.541 L 633.66093,459.541 L 805.15971,538.90218 L 926.28993,538.90218";
    const WALKINGLOGO = "M6358 2083c359,-183 608,-562 614,-987 -6,-612 -495,-1102 -1096,-1096 -606,-6 -1096,484 -1097,1096 1,242 85,474 220,658 30,29 160,243 -132,285 -280,23 -1105,65 -1600,570 -981,1031 -1650,2250 -1820,3990 -56,16 -251,88 -241,307 -10,210 393,671 965,680 138,-9 331,-98 328,-307 3,-118 3,-196 -22,-285 -40,-93 -60,-339 -65,-746 5,-412 408,-1334 986,-1732 0,0 457,3716 -3398,7191 0,0 592,1106 614,1140 125,260 388,348 526,373 59,15 485,60 504,66 39,1 182,27 176,-66 6,-115 -33,-139 -66,-154 -108,-65 -244,-120 -307,-372 0,0 -173,-651 -175,-746 0,0 1847,-1169 3200,-3990 0,0 1911,2195 2697,5985l2083 -920c0,0 84,-50 87,-132 -4,-64 -86,-98 -131,-110 -62,-7 -1222,-124 -1228,-131 -23,7 -82,-3 -88,-66 6,-819 -323,-2184 -592,-2938 -59,-176 -118,-341 -197,-438 -899,-1441 -1218,-2492 -789,-4209 0,0 844,1919 3047,2126 0,0 82,99 198,110 288,-11 381,-768 372,-855 9,-215 -181,-225 -175,-220 -45,-5 -123,-12 -197,110 0,0 -1670,-494 -2149,-2170 -192,-672 -603,-1284 -1052,-1667 -89,-66 -267,-241 0,-350l0 0z";
    const WHEELCHAIRLOGO = "M5995 3256l-123 829 -2538 0c0,0 -536,47 -536,572 0,505 531,562 531,562l2389 0 -118 786 -3229 0c0,0 -217,0 -340,120 -86,86 -204,334 -204,334l-1785 3659c0,0 -211,477 311,752 516,275 840,-247 840,-247l1419 -2904c0,0 118,-186 250,-248 159,-77 286,-79 286,-79l2949 2c0,0 302,0 561,-247 245,-239 286,-506 286,-506l440 -3179c0,0 -9,-658 -699,-706 -522,-36 -690,500 -690,500zm-3465 5523c377,1253 1542,2168 2913,2168 1676,0 3040,-1362 3040,-3042 0,-883 -379,-1677 -983,-2236l182 -1312c1173,740 1957,2055 1957,3548 0,2320 -1880,4198 -4196,4198 -1507,0 -2829,-795 -3564,-1985l651 -1339zm2829 -7601c0,654 525,1181 1178,1181 650,0 1179,-527 1179,-1181 0,-651 -529,-1178 -1179,-1178 -653,0 -1178,527 -1178,1178z";
    const NRFILL = "fill:#ef2721;fill-rule:nonzero;stroke:none";
    const WALKINGFILL = "fill:#003888;fill-rule:nonzero";

    public function nrLogo($intXfrom, $intYfrom)
    {
        if ($this->isHorizontalMode()) {
            $this->genericLogo($intXfrom, $intYfrom, self::NRLOGO, self::NRFILL);
        } else {
            $this->genericLogo($intYfrom, $intXfrom, self::NRLOGO, self::NRFILL);
        }
    }

    public function walkingLogo($intXfrom, $intYfrom)
    {
        if ($this->isHorizontalMode()) {
            $this->genericLogo($intXfrom, $intYfrom, self::WALKINGLOGO, self::WALKINGFILL, 0.005 / 2);
        } else {
            $this->genericLogo($intYfrom, $intXfrom, self::WALKINGLOGO, self::WALKINGFILL, 0.005 / 2);
        }
    }




    public function accessLogo($intXfrom, $intYfrom, $strFill = self::WALKINGFILL)
    {
        if ($this->isHorizontalMode()) {
            $this->genericLogo($intXfrom - 9, $intYfrom - 12, self::WHEELCHAIRLOGO, $strFill, 0.0021);
        } else {
            /*
             *
             * There's a problem with this one...
             */
            $this->genericLogo($intYfrom - 9, $intXfrom - 12, self::WHEELCHAIRLOGO, $strFill, 0.0021);
        }
    }
}

<?php


namespace view\lineDiagramSimple;


class SvgForHtml extends ScalableVectorGraphics
{
    public function htmlimageinsert($intPXwidth = 300, $intPXHeight = 300, $strEmailMode = "html")
    {
        $this->intPXwidth = $intPXwidth;
        $this->intPXHeight = $intPXHeight;
        $strType = "svg+xml";
        $a = "data:image/{$strType};base64," . base64_encode($this->__toString());
        return "<img src=\"{$a}\" style=\"width:{$intPXwidth}" . "px; height:{$intPXHeight}px\">";
    }
}

More code…

<?php


namespace view\lineDiagramSimple;



class ScalableVectorGraphics extends SvgXmlCoreCode
{
    const FONTNORMAL = "styles/fonts/NJFont-Book.otf";
    const FONTSIZEBIG = 15;
    public $intPXwidth = 300;
    public $intPXHeight = 300;
    public  $strFontname;

    public function __construct($intPXwidth = 300, $intPXHeight = 300)
    {
        $this->intPXwidth = $intPXwidth;
        $this->intPXHeight = $intPXHeight;
    }

    public static function calculateTextBoundingBox($strPlacename2, $intXXmore, $intXthis, $intMiddle)
    {
        $intTextWidth = self::getMyTextWidth($strPlacename2);
        $intNumberOfLinesOfText = pre72::count(preg_split("/\n/", $strPlacename2));
        $intFontExtraSize = self::FONTSIZEBIG * $intNumberOfLinesOfText;
        return ["x" => $intXthis - $intTextWidth / 2, "y" => $intMiddle * .5 + $intXXmore - $intFontExtraSize - 2, "w" => $intTextWidth, "h" => $intFontExtraSize + 8];//, "Pidcailly", "Pidcailly");
    }

    public static function getMyTextWidth($strPlacename2)
    {
        $intMaxWidth = 0;
        foreach ($arrWhat = preg_split("/\n/", $strPlacename2) as $strItem) {
            $intLineWidth = ScalableVectorGraphics::getTextWidth($strItem, self::FONTSIZEBIG);
            if ($intLineWidth > $intMaxWidth) {
                $intMaxWidth = $intLineWidth;
            }
        }
        return $intMaxWidth;
    }

    public static function getTextWidth($strSomeText, $intSizePX)
    {
        $strFont = self::FONTNORMAL;
        /*
         *    Fix to deal with the font not being found
         */
        putenv('GDFONTPATH=' . realpath('.'));
        $arrTemp = imagettfbbox($intSizePX, 0, $strFont, $strSomeText);
        return abs($arrTemp[4] - $arrTemp[0]);
    }

    public function addText($strWhat, $intXfrom, $intYfrom, $intSize = 40, $strAnchor = "middle", $strColour = "Blue", $strWeight = "500", $ynUp = true, $ynAddForX = false, $strTextDecor = "")
    {
        self::fixColour($strColour);
        $arrWhat = preg_split("/\n/", $strWhat);
        if ($ynUp) {
            $intYfrom -= $intSize * (count($arrWhat) - 1);
        }
        if ($ynAddForX) {
            $intXfrom -= $intSize * .5 * (count($arrWhat) - 1.5) + 2;
        }
        $intCalcWidth = 0;
        foreach ($arrWhat as $strWhat) {
            switch ($strWhat) {
                case "NR":
                    if ($this->isHorizontalMode()) {
                        $this->nrLogo($intXfrom - 10, $intYfrom - $intSize);
                    } else {
                        $this->nrLogo($intXfrom - $intSize, $intYfrom - 10 + 15);
                        $intYfrom += $intSize;

                    }


                    break;
                case "WALK":
                    if ($this->isHorizontalMode()) {
                        $this->walkingLogo($intXfrom - 10, $intYfrom - $intSize);
                    } else {
                        $this->walkingLogo($intXfrom - $intSize, $intYfrom - 10);
                    }
                    break;
                default:

                    $this->addTextCoreCode($strWhat, $intXfrom, $intYfrom, $strAnchor, $intSize, $strColour, $strWeight, $strTextDecor);
                    $intThisWidth = self::getTextWidth($strWhat, $intSize * .9);
                    if ($intThisWidth > $intCalcWidth) {
                        $intCalcWidth = $intThisWidth;
                    }
                    break;
            }
            if ($this->isHorizontalMode()) {
                $intYfrom += $intSize;
            } else {
                $intXfrom += $intSize;
            }
        }
    }

    private static function fixColour(&$strColour)
    {
        if ($strColour == "transparent") {
            return "";
        }
        if (substr($strColour, 0, 4) == "rgba") {
            return $strColour;
        }
        if (substr($strColour, 0, 1) != "#") {
            $strColour = "#" . tubepalette::getPalette500($strColour);
        }
        return "";
    }

    public function isHorizontalMode()
    {
        return $this->strX == "x";
    }

    public function nrLogo($intXfrom, $intYfrom)
    {
        /*
         *   This is overridden
         *
         */
    }

    public function walkingLogo($intXfrom, $intYfrom)
    {
        /*
         *   This is overridden
         *
         */
    }


    public function addLine($intXfrom, $intYfrom, $intXto, $intYto, $strColour = "Blue", $intStrokeWidth = 15, $strLinecap = "round", $strStrokedasharray = "")
    {
        self::fixColour($strColour);
        if ($strStrokedasharray != "") {
            $strStrokedasharray = " stroke-dasharray=\"{$strStrokedasharray}\" ";
        }
        $this->strStore .= "<line {$this->strX}1=\"{$intXfrom}\" {$this->strY}1=\"{$intYfrom}\" {$this->strX}2=\"{$intXto}\" {$this->strY}2=\"{$intYto}\" stroke-width=\"{$intStrokeWidth}\" stroke=\"$strColour\" stroke-linecap=\"{$strLinecap}\" $strStrokedasharray  />";
    }

    public function genericLogo($intXfrom, $intYfrom, $strPathDcode, $strStyleCode, $fpScale = 0.04)
    {
        $intXS = -550;
        $intYS = -220;
        $fpCX = $intXS * $fpScale;
        $fpCY = $intYS * $fpScale;
        $fpCX += $intXfrom;
        $fpCY += $intYfrom;
        $strID = "layer" . rand(1E6, 1E8);
        $this->strStore .= "<g transform=\"translate({$fpCX},{$fpCY}) scale($fpScale)  \" id=\"{$strID}\" > <path d=\"{$strPathDcode}\" id=\"{$strID}a\" style=\"{$strStyleCode}\" /></g>";
    }

    public function startAhref($strURL)
    {
        $this->strStore .= "<a xlink:href=\"{$strURL}\">";
    }

    public function endAhref()
    {
        $this->strStore .= "</a>";
    }


    public function addRectangle($intXfrom, $intYfrom, $intWidth = 100, $intHeight = 100, $strFill = "White", $strStoke = "Black", $intStrokeWidth = 1)
    {
        self::fixColour($strStoke);
        self::fixColour($strFill);
//        $this->strStore .= " <rect  {$this->strX}=\"{$intXfrom}\" {$this->strY}=\"{$intYfrom}\" width=\"$intWidth\" height=\"$intHeight\" fill=\"$strFill\" stroke-width=\"{$intStrokeWidth}\" stroke=\"{$strStoke}\" />";

        $this->addRectangleCore($intXfrom, $intYfrom, $intWidth, $intHeight, $strFill, $strStoke, $intStrokeWidth);

        if ($strFill == "#ffce00") {
            return "#ffffff";
        }
        return $strFill;
    }

    public function setSwap($ynSwap)
    {
        if ($ynSwap) {
            $this->strX = "y";
            $this->strY = "x";
        } else {
            $this->strX = "x";
            $this->strY = "y";
        }
    }

    public function addLineOfDots($intXfrom, $intYfrom, $intXto, $strColour = "Blue", $intStrokeWidth = 15)
    {
        $intTwo = 25;
        self::fixColour($strColour);
        $intThisX = $intXfrom;
        do {
            $this->addCircle($intThisX, $intYfrom, $intStrokeWidth / 2, $strColour);
            $intThisX += $intTwo / 2;
        } while ($intThisX < $intXto);
    }

    public function addCircle($intXfrom, $intYfrom, $intRadius = 40, $strColour = "Blue")
    {
        self::fixColour($strColour);
//        $this->strStore .= "<circle c{$this->strX}=\"{$intXfrom}\" c{$this->strY}=\"{$intYfrom}\" r=\"{$intRadius}\" fill=\"{$strColour}\" stroke=\"{$strColour}\"  />";
        $this->circleCore($intXfrom, $intYfrom, $intRadius, $strColour);
    }



    public function addBezierCurveQuadratic($intXfrom, $intYfrom, $intXto, $intYto, $strColour = "Blue", $intStrokeWidth = 15, $strLinecap = "round")
    {
        self::fixColour($strColour);
        if ($this->strX == "x") {
            $strControlPoints = " Q $intXto,$intYfrom  ";
            $this->strStore .= "<path d=\"M$intXfrom, $intYfrom  {$strControlPoints} $intXto, $intYto \" fill=\"none\" stroke-width=\"{$intStrokeWidth}\" stroke=\"$strColour\" stroke-linecap=\"{$strLinecap}\" />";
        } else {
            $strControlPoints = " Q $intYto,$intXfrom  ";
            $this->strStore .= "<path d=\"M$intYfrom, $intXfrom  {$strControlPoints} $intYto, $intXto \" fill=\"none\" stroke-width=\"{$intStrokeWidth}\" stroke=\"$strColour\" stroke-linecap=\"{$strLinecap}\" />";
        }
    }
}

<?php

namespace view\lineDiagramSimple;

use view\helper\xml;

class SvgXmlCoreCode
{
    public $strStore = "";
    public $strX = "x";
    public $strY = "y";

    public function __toString()
    {
        return xml::wrapTag($this->strStore, "svg", "xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"  version=\"1.1\" width=\"{$this->intPXwidth}\" height=\"{$this->intPXHeight}\" preserveAspectRatio=\"xMinYMin slice\" viewBox=\"0 0 {$this->intPXwidth} {$this->intPXHeight}\"");
    }

    public final function addTextCoreCode($strWhat, $intXfrom, $intYfrom, $strAnchor, $intSize, $strColour, $strWeight, $strTextDecor)
    {
        $this->strStore .= "<text {$this->strX}=\"{$intXfrom}\" {$this->strY}=\"{$intYfrom}\"  text-anchor=\"{$strAnchor}\" font-size=\"{$intSize}\" fill=\"{$strColour}\" font-weight = \"{$strWeight}\" font-family=\"{$this->strFontname}\" xtext-decoration=\"{$strTextDecor}\">{$strWhat}</text>";
    }

    public function addRectangleCore($intXfrom, $intYfrom, $intWidth, $intHeight, $strFill, $strStoke, $intStrokeWidth)
    {
        $this->strStore .= " <rect  {$this->strX}=\"{$intXfrom}\" {$this->strY}=\"{$intYfrom}\" width=\"$intWidth\" height=\"$intHeight\" fill=\"$strFill\" stroke-width=\"{$intStrokeWidth}\" stroke=\"{$strStoke}\" />";
    }

    public final function circleCore($intXfrom, $intYfrom, $intRadius, $strColour)
    {
        $this->strStore .= "<circle c{$this->strX}=\"{$intXfrom}\" c{$this->strY}=\"{$intYfrom}\" r=\"{$intRadius}\" fill=\"{$strColour}\" stroke=\"{$strColour}\"  />";
    }

    public final function circleCoreStroke($intXfrom, $intYfrom, $intRadius, $strColour, $strStroke)
    {
        $this->strStore .= "<circle c{$this->strX}=\"{$intXfrom}\" c{$this->strY}=\"{$intYfrom}\" r=\"{$intRadius}\" fill=\"{$strColour}\" stroke=\"{$strStroke}\"  />";
    }
}

<?php
/**
 * Created by PhpStorm.
 * User: Briantist
 * Date: 12/01/2017
 * Time: 17:02
 */

namespace view\helper;

use pseph\nff\formation\SpecilisedHtmlHeaders;

class xml extends core
{
    const COMPRESSXML = true;

    public static function setXML($intSeconds = 29)
    {
        if (self::COMPRESSXML)
            if (!core::isWindowsMachine()) {
                core::startObGzHandler();
            }
        SpecilisedHtmlHeaders::outputHTTPheaders($intSeconds, "application/xml; charset=utf-8");
        echo "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
    }

    public static function wrapTag($srtWhat, $strTag, $strParams = "")
    {
        if ($strParams != "") {
            $strParams = " " . $strParams;
        }
        if (is_array($srtWhat)) {
            $srtWhat = "[]";
        }
        if (is_object($srtWhat)) {
            $srtWhat = "object";
        }
        return "<{$strTag}{$strParams}>{$srtWhat}</{$strTag}>";
    }
}

Hi @Briantist,

Thank you very much for you help, now I have to identify how I can use the code in my android application since it is PHP code, I am converting it. I know that it is complex but I am trying to achieve to draw map. If not then I will creating same map in MS Paint :slight_smile:

Thank you again.