Zeliax
Zeliax

Reputation: 5386

Text is vertically stretched on my canvas, making it unreadable

I have a canvas that I am drawing on top of a OpenLayers map. The canvas is colored in gradient colors and now I am trying to add text on top of it.

However the text seems to be stretched making it completely unreadable.

function createSpeedBar(min, max, speeds) {
    //List of integer speeds
    var fullSpeeds = [];
    //List of unique speed values (no duplicates)
    var uniqueSpeeds = [];

    //Filling fullSpeeds using minimum and maximum values
    for (i = min; i <= max; i++) {
        fullSpeeds.push(i);
    }

    //Filling uniqueSpeeds with unique values
    $.each(speeds, function (i, el) {
        if ($.inArray(el, uniqueSpeeds) === -1) uniqueSpeeds.push(el);
    });

    //Sorting uniqueSpeeds (low to high)
    uniqueSpeeds = uniqueSpeeds.sort(function (a, b) {
        return a - b;
    });

    //Getting canvas element
    var canvas = document.getElementById("speedList");
    var context = canvas.getContext("2d");
    context.rect(0, 0, canvas.width, canvas.height);

    var grd = context.createLinearGradient(0, 0, 0, 170);
    var hslMin = 0;
    var hslMax = 240;

    //Defining hslColors using uniqueSpeeds
    var hslValues = uniqueSpeeds.map(function (value) {
        if ($.inArray(value, fullSpeeds)){
            return {
                h: Math.ceil(((value - min) / (max - min)) * (hslMax - hslMin) + hslMin),
                s: 100,
                l: 50,
                full: true,
                speed: value
            };
        } else {
            return {
                h: Math.ceil(((value - min) / (max - min)) * (hslMax - hslMin) + hslMin),
                s: 100,
                l: 50,
                full: false
            };
        };
    });

    var count = 1;
    var length = hslValues.length;

    //Gradient coloring using hslColors
    hslValues.forEach(function (value) {
        var color = 'hsl(' + value.h + ',' + value.s + '%,' + value.l +    '%)';
        grd.addColorStop(count / length, color)
        count += 1;
    });

    context.fillStyle = grd;
    context.fill();

    //Setting up coloring and drawing of text
    count = 1
    var height = canvas.height;
    var width = canvas.width;
    var elementHeight = height / length;

    //Drawing text on canvas
    hslValues.forEach(function (value) {
        context.font = "12px Arial";
        context.textAlign = "center";
        context.textBaseline = "middle";
        context.fillStyle = "black";
        if (value.full === true) {
            context.fillText(value.speed, width / 2, ((elementHeight / 2) + elementHeight * count));
        }
        count += 1;
    });
}

As it might be clear I am trying to create a bar displaying the intensities of the speed on the map where I have colored some markers. However the text on the canvas comes out like this:

enter image description here

Right now I have made the height of the canvas inherit the height of the map which is 500. The width of the canvas is set manually using css:

html

<div id="map" class="map">
    <canvas id="speedList"></canvas>
</div>

css

#map {
    position: relative;
    height: 500px;
}

#speedList {
    position: absolute;
    right: 10px;
    top: 0;
    bottom: 0;
    width: 20px;
    z-index: 1000;
    height: inherit;
    margin: 0;
    padding: 0;
}

I am currently working on a Fiddle, but it takes a little time to reproduce, and I bet the issue is not that big, so hopefully someone knows how to fix it before I finish the Fiddle.

Upvotes: 1

Views: 1536

Answers (1)

Frits
Frits

Reputation: 7614

The main problem here is the CSS adjustment of the width and height of the canvas element.

If it helps to understand the problem, think of <canvas> the same way you would think of <img/>, if you take an img, and give it a width and height of 50 x 500, it would stretch too.

The fix is to ensure that you set the width an height of the canvas element itself, before it processes it's content, like this:

<canvas id="speedList" width="20" height="500"></canvas>

You then also need to make sure your remove the width and height properties inside your CSS, like this:

#map {
    position: relative;
    height: 500px;
}

#speedList {
    position: absolute;
    right: 10px;
    top: 0;
    bottom: 0;
    z-index: 1000;
    margin: 0;
    padding: 0;
}

Upvotes: 3

Related Questions