1

我正在使用 HtML5、Canvas、Javascript,我创建了一个页面,其中正在读取 excel 文件,并且它的值显示在速度计中..我的整个代码我工作正常,但是我不能做的另一件事是,假设我们有像这样的excel文件中的五个值

    t1    50
    t2    90
    t3    10
    t4    25
    t5    36

所以根据我的代码,它将在一个车速表中显示所有值,但我想在不同的车速表上显示它,比如一个车速表中的 50,另一个车速表中的 90,另一个车速表中的 10,依此类推..我不能这样做..我的代码如下

           <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>Speedometer HTML5 Canvas</title>

        <script src="script copy.js">

    </script>

    </head>
    <body onload='draw(0);'>
        <canvas id="tutorial" width="440" height="220">

                Canvas not available.
            </canvas>
        <div id="divHidden" style="visibility: hidden; width: 0px; height: 0px">
            <form id="drawTemp">
            <input type="text" id="txtSpeed" name="txtSpeed" value="20" maxlength="2" />
            <input type="button" value="Draw" onclick="drawWithInputValue();">
            <input type="file" id="file" onchange="checkfile(this);" />
           <input type="button" id="btnSubmit" onclick="readdata(1, 2)" value="Submit" /> 


        <button onclick="myStopFunction()">Stop Meter</button>


            </form>
        </div>
    </body>
    </html>

    <script type="text/javascript" language="javascript">


        var myVar=setInterval(function(){readdata(1,2)},2000);
        function myStopFunction()
        {
            clearInterval(myVar);
        }


        function checkfile(sender) {
            var validExts = new Array(".xlsx", ".xls", ".csv");
            var fileExt = sender.value;
            fileExt = fileExt.substring(fileExt.lastIndexOf('.'));
            if (validExts.indexOf(fileExt) < 0) {
                alert("Invalid file selected, valid files are of " +
                   validExts.toString() + " types.");
                return false;
            }
            else return true;

        }
    var xVal = 1;
    var yVal = 2

        function readdata(x,y) {
            x = xVal;
            y = yVal;
            try {
                var excel = new ActiveXObject("Excel.Application");
                excel.Visible = false;
                var excel_file = excel.Workbooks.Open("D:\\Test.xls");// alert(excel_file.worksheets.count);
                var excel_sheet = excel_file.Worksheets("Sheet1");
                var data = excel_sheet.Cells(x, y).Value;
                //alert(data);
                drawWithexcelValue(data);
                xVal = xVal + 1;
                if(data==null || data=="")
                { 
                myStopFunction(); 
                }
                excel.Application.Quit();

            }
            catch (ex) {
                alert(ex);
            }
        }
    </script>
    and for speedometer here is my code



   /*jslint plusplus: true, sloppy: true, indent: 4 */
(function() {
    "use strict";
    // this function is strict...
} ());

var iCurrentSpeed = 20,
    iTargetSpeed = 20,
    bDecrement = null,
    job = null;

function degToRad(angle) {
    // Degrees to radians
    return ((angle * Math.PI) / 180);
}

function radToDeg(angle) {
    // Radians to degree
    return ((angle * 180) / Math.PI);
}

function drawLine(options, line) {
    // Draw a line using the line object passed in
    options.ctx.beginPath();

    // Set attributes of open
    options.ctx.globalAlpha = line.alpha;
    options.ctx.lineWidth = line.lineWidth;
    options.ctx.fillStyle = line.fillStyle;
    options.ctx.strokeStyle = line.fillStyle;
    options.ctx.moveTo(line.from.X,
        line.from.Y);

    // Plot the line
    options.ctx.lineTo(
        line.to.X,
        line.to.Y
    );

    options.ctx.stroke();
}

function createLine(fromX, fromY, toX, toY, fillStyle, lineWidth, alpha) {
    // Create a line object using Javascript object notation
    return {
        from: {
            X: fromX,
            Y: fromY
        },
        to: {
            X: toX,
            Y: toY
        },
        fillStyle: fillStyle,
        lineWidth: lineWidth,
        alpha: alpha
    };
}

function drawOuterMetallicArc(options) {
    /* Draw the metallic border of the speedometer 
    * Outer grey area
    */
    options.ctx.beginPath();

    // Nice shade of grey
    options.ctx.fillStyle = "rgb(127,127,127)";

    // Draw the outer circle
    options.ctx.arc(options.center.X,
        options.center.Y,
        options.radius,
        0,
        Math.PI,
        true);

    // Fill the last object
    options.ctx.fill();
}

function drawInnerMetallicArc(options) {
    /* Draw the metallic border of the speedometer 
    * Inner white area
    */

    options.ctx.beginPath();

    // White
    options.ctx.fillStyle = "rgb(255,255,255)";

    // Outer circle (subtle edge in the grey)
    options.ctx.arc(options.center.X,
                    options.center.Y,
                    (options.radius / 100) * 90,
                    0,
                    Math.PI,
                    true);

    options.ctx.fill();
}

function drawMetallicArc(options) {
    /* Draw the metallic border of the speedometer
    * by drawing two semi-circles, one over lapping
    * the other with a bot of alpha transparency
    */

    drawOuterMetallicArc(options);
    drawInnerMetallicArc(options);
}

function drawBackground(options) {
    /* Black background with alphs transparency to
    * blend the edges of the metallic edge and
    * black background
    */
    var i = 0;

    options.ctx.globalAlpha = 0.2;
    options.ctx.fillStyle = "rgb(0,0,0)";

    // Draw semi-transparent circles
    for (i = 170; i < 180; i++) {
        options.ctx.beginPath();

        options.ctx.arc(options.center.X,
            options.center.Y,
            i,
            0,
            Math.PI,
            true);

        options.ctx.fill();
    }
}

function applyDefaultContextSettings(options) {
    /* Helper function to revert to gauges
    * default settings
    */

    options.ctx.lineWidth = 2;
    options.ctx.globalAlpha = 0.5;
    options.ctx.strokeStyle = "rgb(255, 255, 255)";
    options.ctx.fillStyle = 'rgb(255,255,255)';
}

function drawSmallTickMarks(options) {
    /* The small tick marks against the coloured
    * arc drawn every 5 mph from 10 degrees to
    * 170 degrees.
    */

    var tickvalue = options.levelRadius - 8,
        iTick = 0,
        gaugeOptions = options.gaugeOptions,
        iTickRad = 0,
        onArchX,
        onArchY,
        innerTickX,
        innerTickY,
        fromX,
        fromY,
        line,
        toX,
        toY;

    applyDefaultContextSettings(options);

    // Tick every 20 degrees (small ticks)
    for (iTick = 10; iTick < 180; iTick += 20) {

        iTickRad = degToRad(iTick);

        /* Calculate the X and Y of both ends of the
        * line I need to draw at angle represented at Tick.
        * The aim is to draw the a line starting on the 
        * coloured arc and continueing towards the outer edge
        * in the direction from the center of the gauge. 
        */

        onArchX = gaugeOptions.radius - (Math.cos(iTickRad) * tickvalue);
        onArchY = gaugeOptions.radius - (Math.sin(iTickRad) * tickvalue);
        innerTickX = gaugeOptions.radius - (Math.cos(iTickRad) * gaugeOptions.radius);
        innerTickY = gaugeOptions.radius - (Math.sin(iTickRad) * gaugeOptions.radius);

        fromX = (options.center.X - gaugeOptions.radius) + onArchX;
        fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + onArchY;
        toX = (options.center.X - gaugeOptions.radius) + innerTickX;
        toY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY;

        // Create a line expressed in JSON
        line = createLine(fromX, fromY, toX, toY, "rgb(127,127,127)", 3, 0.6);

        // Draw the line
        drawLine(options, line);

    }
}

function drawLargeTickMarks(options) {
    /* The large tick marks against the coloured
    * arc drawn every 10 mph from 10 degrees to
    * 170 degrees.
    */

    var tickvalue = options.levelRadius - 8,
        iTick = 0,
        gaugeOptions = options.gaugeOptions,
        iTickRad = 0,
        innerTickY,
        innerTickX,
        onArchX,
        onArchY,
        fromX,
        fromY,
        toX,
        toY,
        line;

    applyDefaultContextSettings(options);

    tickvalue = options.levelRadius - 2;
//alert(tickValue);
    // 10 units (major ticks)
    for (iTick = 10; iTick < 180; iTick += 10) {

        iTickRad = degToRad(iTick);

        /* Calculate the X and Y of both ends of the
        * line I need to draw at angle represented at Tick.
        * The aim is to draw the a line starting on the 
        * coloured arc and continueing towards the outer edge
        * in the direction from the center of the gauge. 
        */

        onArchX = gaugeOptions.radius - (Math.cos(iTickRad) * tickvalue);
        onArchY = gaugeOptions.radius - (Math.sin(iTickRad) * tickvalue);
        innerTickX = gaugeOptions.radius - (Math.cos(iTickRad) * gaugeOptions.radius);
        innerTickY = gaugeOptions.radius - (Math.sin(iTickRad) * gaugeOptions.radius);

        fromX = (options.center.X - gaugeOptions.radius) + onArchX;
        fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + onArchY;
        toX = (options.center.X - gaugeOptions.radius) + innerTickX;
        toY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY;

        // Create a line expressed in JSON
        line = createLine(fromX, fromY, toX, toY, "rgb(127,127,127)", 3, 0.6);

        // Draw the line
        drawLine(options, line);
    }
}

function drawTicks(options) {
    /* Two tick in the coloured arc!
    * Small ticks every 5
    * Large ticks every 10
    */
    drawSmallTickMarks(options);
    drawLargeTickMarks(options);
}

function drawTextMarkers(options) {
    /* The text labels marks above the coloured
    * arc drawn every 10 mph from 10 degrees to
    * 170 degrees.
    */
    var innerTickX = 0,
        innerTickY = 0,
        iTick = 0,
        gaugeOptions = options.gaugeOptions,
        iTickToPrint = 0;

    applyDefaultContextSettings(options);

    // Font styling
    options.ctx.font = 'italic 10px sans-serif';
    options.ctx.textBaseline = 'top';

    options.ctx.beginPath();

    // Tick every 20 (small ticks)
    for (iTick = 10; iTick < 180; iTick += 20) {

        innerTickX = gaugeOptions.radius - (Math.cos(degToRad(iTick)) * gaugeOptions.radius);
        innerTickY = gaugeOptions.radius - (Math.sin(degToRad(iTick)) * gaugeOptions.radius);

        // Some cludging to center the values (TODO: Improve)
        if (iTick <= 10) {
            options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX,
                    (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5);
        } else if (iTick < 50) {
            options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX - 5,
                    (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5);
        } else if (iTick < 90) {
            options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX,
                    (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY);
        } else if (iTick === 90) {
            options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 4,
                    (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY);
        } else if (iTick < 145) {
            options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 10,
                    (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY);
        } else {
            options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 15,
                    (gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5);
        }

        // MPH increase by 10 every 20 degrees
        iTickToPrint += Math.round(2160 / 216);
    }

    options.ctx.stroke();
}

function drawSpeedometerPart(options, alphaValue, strokeStyle, startPos) {
    /* Draw part of the arc that represents
    * the colour speedometer arc
    */

    options.ctx.beginPath();

    options.ctx.globalAlpha = alphaValue;
    options.ctx.lineWidth = 5;
    options.ctx.strokeStyle = strokeStyle;

    options.ctx.arc(options.center.X,
        options.center.Y,
        options.levelRadius,
        Math.PI + (Math.PI / 360 * startPos),
        0 - (Math.PI / 360 * 10),
        false);

    options.ctx.stroke();
}

function drawSpeedometerColourArc(options) {
    /* Draws the colour arc.  Three different colours
    * used here; thus, same arc drawn 3 times with
    * different colours.
    * TODO: Gradient possible?
    */

    var startOfGreen = 10,
        endOfGreen = 200,
        endOfOrange = 280;

    drawSpeedometerPart(options, 1.0, "rgb(82, 240, 55)", startOfGreen);
    drawSpeedometerPart(options, 0.9, "rgb(198, 111, 0)", endOfGreen);
    drawSpeedometerPart(options, 0.9, "rgb(255, 0, 0)", endOfOrange);

}

function drawNeedleDial(options, alphaValue, strokeStyle, fillStyle) {
    /* Draws the metallic dial that covers the base of the
    * needle.
    */
    var i = 0;

    options.ctx.globalAlpha = alphaValue;
    options.ctx.lineWidth = 3;
    options.ctx.strokeStyle = strokeStyle;
    options.ctx.fillStyle = fillStyle;

    // Draw several transparent circles with alpha
    for (i = 0; i < 30; i++) {

        options.ctx.beginPath();
        options.ctx.arc(options.center.X,
            options.center.Y,
            i,
            0,
            Math.PI,
            true);

        options.ctx.fill();
        options.ctx.stroke();
    }
}

function convertSpeedToAngle(options) {
    /* Helper function to convert a speed to the 
    * equivelant angle.
    */
    var iSpeed = (options.speed / 10),
        iSpeedAsAngle = ((iSpeed * 20) + 10) % 180;

    // Ensure the angle is within range
    if (iSpeedAsAngle > 180) {
        iSpeedAsAngle = iSpeedAsAngle - 180;
    } else if (iSpeedAsAngle < 0) {
        iSpeedAsAngle = iSpeedAsAngle + 180;
    }

    return iSpeedAsAngle;
}

function drawNeedle(options) {
    /* Draw the needle in a nice read colour at the
    * angle that represents the options.speed value.
    */

    var iSpeedAsAngle = convertSpeedToAngle(options),
        iSpeedAsAngleRad = degToRad(iSpeedAsAngle),
        gaugeOptions = options.gaugeOptions,
        innerTickX = gaugeOptions.radius - (Math.cos(iSpeedAsAngleRad) * 20),
        innerTickY = gaugeOptions.radius - (Math.sin(iSpeedAsAngleRad) * 20),
        fromX = (options.center.X - gaugeOptions.radius) + innerTickX,
        fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY,
        endNeedleX = gaugeOptions.radius - (Math.cos(iSpeedAsAngleRad) * gaugeOptions.radius),
        endNeedleY = gaugeOptions.radius - (Math.sin(iSpeedAsAngleRad) * gaugeOptions.radius),
        toX = (options.center.X - gaugeOptions.radius) + endNeedleX,
        toY = (gaugeOptions.center.Y - gaugeOptions.radius) + endNeedleY,
        line = createLine(fromX, fromY, toX, toY, "rgb(255,0,0)",5, 0.9);

    drawLine(options, line);

    // Two circle to draw the dial at the base (give its a nice effect?)
    drawNeedleDial(options, 0.6, "rgb(127, 127, 127)", "rgb(255,255,255)");
    drawNeedleDial(options, 0.2, "rgb(127, 127, 127)", "rgb(127,127,127)");

}

function buildOptionsAsJSON(canvas, iSpeed) {
    /* Setting for the speedometer 
    * Alter these to modify its look and feel
    */

    var centerX = 210,
        centerY = 210,
        radius = 140,
        outerRadius = 200;

    // Create a speedometer object using Javascript object notation
    return {
        ctx: canvas.getContext('2d'),
        speed: iSpeed,
        center: {
            X: centerX,
            Y: centerY
        },
        levelRadius: radius - 10,
        gaugeOptions: {
            center: {
                X: centerX,
                Y: centerY
            },
            radius: radius
        },
        radius: outerRadius
    };
}

function clearCanvas(options) {
    options.ctx.clearRect(0, 0, 800, 600);
    applyDefaultContextSettings(options);
}

function draw() {
    /* Main entry point for drawing the speedometer
    * If canvas is not support alert the user.
    */

    var canvas = document.getElementById('tutorial'),
        options = null;

    // Canvas good?
    if (canvas !== null && canvas.getContext) {
        options = buildOptionsAsJSON(canvas, iCurrentSpeed);

        // Clear canvas
        clearCanvas(options);

        // Draw the metallic styled edge
        drawMetallicArc(options);

        // Draw thw background
        drawBackground(options);

        // Draw tick marks
        drawTicks(options);

        // Draw labels on markers
        drawTextMarkers(options);

        // Draw speeometer colour arc
        drawSpeedometerColourArc(options);

        // Draw the needle and base
        drawNeedle(options);

    } else {
        alert("Canvas not supported by your browser!");
    }

    if (iTargetSpeed == iCurrentSpeed) {
        clearTimeout(job);
        return;
    } else if (iTargetSpeed < iCurrentSpeed) {
        bDecrement = true;
    } else if (iTargetSpeed > iCurrentSpeed) {
        bDecrement = false;
    }

    if (bDecrement) {
        if (iCurrentSpeed - 10 < iTargetSpeed)
            iCurrentSpeed = iCurrentSpeed - 1;
        else
            iCurrentSpeed = iCurrentSpeed - 5;
    } else {

        if (iCurrentSpeed + 10 > iTargetSpeed)
            iCurrentSpeed = iCurrentSpeed + 1;
        else
            iCurrentSpeed = iCurrentSpeed + 5;
    }

    job = setTimeout("draw()", 5);
}

function drawWithInputValue() {

    var txtSpeed = document.getElementById('txtSpeed'); //alert(txtSpeed.value);

    if (txtSpeed !== null) {

        iTargetSpeed = txtSpeed.value;

        // Sanity checks
        if (isNaN(iTargetSpeed)) {
            iTargetSpeed = 0;
        } else if (iTargetSpeed < 0) {
            iTargetSpeed = 0;
        } else if (iTargetSpeed > 80) {
            iTargetSpeed = 80;

        }

        job = setTimeout("draw()", 5);

    }

}

function drawWithexcelValue(val) {

    var txtSpeed = val; //alert(txtSpeed.value);
    if (txtSpeed !== null) {

        iTargetSpeed = txtSpeed;

        // Sanity checks
        if (isNaN(iTargetSpeed)) {
            iTargetSpeed = 0;
        } else if (iTargetSpeed < 0) {
            iTargetSpeed = 0;
        } else if (iTargetSpeed > 80) {
            iTargetSpeed = 80;
        }

        job = setTimeout("draw()", 5);

    }

}
4

1 回答 1

1

您可以通过将 x-offsets (1-5) 添加到绘图函数来生成多个速度计

在此处输入图像描述

我假设您的选项变量存储 t1,t2,t3,t4,t5 及其速度:

您没有提供足够的关于您的选项的代码,因此简化的选项可能如下所示。

(根据您的实际情况进行调整):

    options=[
    {t:1,speed:50},
    {t:2,speed:90},
    {t:3,speed:10},
    {t:4,speed:25},
    {t:5,speed:36},
    ];

然后在你的绘图函数中,你需要遍历每个“t”:

    function draw(){

        // Clear canvas

        for(varti=0;t<options.length;t++){

            option=options[t];

            // Draw the metallic styled edge
            // Draw thw background
            // Draw tick marks
            // Draw labels on markers
            // Draw speeometer colour arc
            // Draw the needle and base
        }

    }

在您的 drawMetallicArc (etc) 函数中,您将根据您正在绘制的“t”绘制一个从左侧偏移的速度计:

还假设您希望每个速度计的中心间隔 50 像素。

然后你可以像这样计算 5 个速度表中的每一个的 center-x

centerX = t * 50;

为了说明,假设每个速度计的半径为 15,y 坐标为 60。

您的 drawMetallicArc 函数将如下所示:

    function drawMetallicArc(option){
        var y=60;
        var radius=15;
        var x=option.t*50;

        ctx.beginPath();
        ctx.arc(x,y,radius,0,Math.PI*2,false);
        ctx.closePath();
        ctx.strokeStyle="blue";
        ctx.stroke();
    }

当然,您可以类似地修改其他每个绘制函数以使用 x 偏移量。

这是代码和小提琴:http: //jsfiddle.net/m1erickson/93SY5/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; padding:20px;}
    #canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");


    options=[
    {t:1,speed:50},
    {t:2,speed:90},
    {t:3,speed:10},
    {t:4,speed:25},
    {t:5,speed:36},
    ];

    draw();

    function draw(){

        // Clear canvas

        for(var i=0;i<options.length;i++){

            option=options[i];

            // Draw the metallic styled edge
            drawMetallicArc(option);

            // Draw thw background

            // Draw tick marks

            // Draw labels on markers
            drawTextMarkers(option);

            // Draw speeometer colour arc

            // Draw the needle and base

        }

    }

    function drawMetallicArc(option){
        var y=60;
        var radius=15;
        var x=option.t*50;

        ctx.beginPath();
        ctx.arc(x,y,radius,0,Math.PI*2,false);
        ctx.closePath();
        ctx.strokeStyle="blue";
        ctx.stroke();
    }

    function drawTextMarkers(option){
        var y=60
        var radius=15
        var top=y-radius-5;
        var x=option.t*50-5;  // -5 for digit spacing
        ctx.fillText(option.speed,x,top);
    }


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=350 height=100></canvas>
</body>
</html>

【补充:补充看代码】

600 多行代码需要看很多......无论如何:

现在,您正在 readdata() 中读取 1 个 excel 值,然后调用

drawWithexcelValue(data);

我假设您将更改它以在 readdata() 中读取 5 个 excel 值——t1、t2、t3、t4、t5

var multipleData = [50,90,10,25,36];

drawWithexcelValue(multipleData);

您的 drawWithexcelValue 将值限制在 0-80 的范围内,然后调用 draw()

在draw中,需要对多值数组中的每一个值进行处理

for(var t=0;t<multipleData.length;t++){

    // build options for this “t” value
    options = buildOptionsAsJSON(canvas,multipleData[t],t);

    // now call all draw-X functions using current  “options”

}

buildOptionsAsJSON 使用“t”值来改变当前速度计的中心点:

关键是这个中心 X 计算对于每个新的速度表向右移动:

X = outerRadius * t + 10;    // +10 is just to space the speedometers apart

这是完整的 buildOptionsAsJSON():

function buildOptionsAsJSON(canvas, iSpeed, t) {

    var centerX = 0,
        centerY = 210,
        radius = 140,
        outerRadius = 200;

    // Create a speedometer object using Javascript object notation
    return {
        ctx: canvas.getContext('2d'),
        speed: iSpeed,
        center: {
            X: outerRadius * t + 10,  // 10 is horizontal spacing
            Y: centerY
        },
        levelRadius: radius - 10,
        gaugeOptions: {
            center: {
                X: outerRadius * t +10,  // +10 is horizontal spacing
                Y: centerY
            },
            radius: radius
        },
        radius: outerRadius
    };
}
于 2013-07-30T18:23:18.543 回答