Touchscreen

Posted on
  • In many previous projects I used a 2.8" TFT 262K Color LCD display with resistive touchscreen. Since the display had no touchscreen controller, I implemented one on Espruino (Resistive Touchscreen directly (no touch controller)). Recently I wanted to use the display again, but for whatever reason it turned out to be dead not only like a possum, but really really dead. So I ordered some cheaper once of 2.2" size, since needed them just to verify code for the ILI9341 display controller.

    The cheap 2.4" display showed though up with a XPT2046 touchscreen controller from XPTEK TECHNOLOGY CO., LTD, SHENZHEN. After consulting the data sheet it seems that the XPT2046 is functionally about equal to Burr-Brown's / TI's ADS7843 and thus Espruino's ADS7843 module works... at least, it returns coordinates... dodged that bullet... easily...

    But from there on in went tricky to say the least... and unfortunately ended with the conclusion: module useless (from the point of usable values,.. and more), because the user's touch accuracy is about +- 2..3 pixels... but the module error is up to 32... just not useful for a touch UI.

    Why?

    Below code and and attached shot show. The code sets up the display and the touch screen, then draws calibration markers in all corners and the center and then logs values for calibration.

    // TFT24TRCportraitCalibr.js
    //
    //  2.4" 240x320 262K Color TFT LCD ILI9341 on SPI1 with 
    //  Resistive Touch Screen Controller XPT2046 on SPI2
    //  using out of box ILI9341 and ADS7843 modules.
    //
    // Wiring:
    //  2.4"
    //  DSP                  PICO [<---USB
    //   1   VCC      red     3   3.3            shared
    //   2   GND      blk     1   GND            shared
    //   3   CS       blu     7   B6   CS        LCD
    //   4   RST      brn     9   A8   reset RST LCD
    //   5   D/C      grn     8   B7   D/C       LCD
    //   6   MOSI     ylw     6   B5   SPI1 MOSI LCD
    //   7   SCK      wht     4   B3   SPI1 SCK  LCD
    //   8   LED      org    18   A5   LED       LCD
    //   9   MISO     grn     5   B4   SPI1 MISO LCD
    //  10   T_CLK    wht    23   B13  SPI2 SCK  Touch
    //  11   T_CS     ylw    22   B10  CS        Touch
    //  12   T_MOSI   grn    25   B15  SPI2 MOSI Touch
    //  13   T_MISO   blu    24   B14  SPI2 MISO Touch
    //  14   T_IRQ    blk    21   B1   IRQ       Touch
    
    var dW = 240, dH = 320, dsp, dMod = require("ILI9341"),
        tSPI=SPI2, tCs = B10, tIrq = B1, 
        touch, tMod = require("ADS7843");
    
    // marker specs (lik dice face 5; top left to bottom right)
    var mrks =
        [{i:1, label:"topLeft"    , x: 20, y: 20, xOff: 14, yOff:-6}
        ,{i:2, label:"topRight"   , x:220, y: 20, xOff:-66, yOff:-6}
        ,{i:3, label:"center"     , x:120, y:160, xOff:-29, yOff:14}
        ,{i:4, label:"bottomLeft" , x: 20, y:300, xOff: 14, yOff:-6}
        ,{i:5, label:"bottomRight", x:220, y:300, xOff:-74, yOff:-6}
        ];
    var mSiz = 9; // half of marker size, (0.7 of font size)
    
    // print marker at x/y of size s with x/y label
    function mrkr(d,x,y,s,xOff,yOff) {
      dsp.setColor(1,1,1);
      dsp.drawRect(x-s,y-s,x+s,y+s);
      dsp.drawLine(x-s,y,x+s,y);
      dsp.drawLine(x,y-s,x,y+s);
      dsp.setFontVector(s / 0.7);
      dsp.drawString(x + " / " + y, x+xOff, y+yOff);
    }
    
    function average(arry) { // return avarage of array values
      return arry.reduce(
        function(p,c) { return p + c; },0) / arry.length; }
    
    function logAverage(seq,xs,ys) { // log x / y average
      var x = Math.round(average(xs)), 
          y = Math.round(average(ys));
      console.log(
          seq + 1
        , mrks[seq].label
        , mrks[seq].x, mrks[seq].y
        , x ,"(" + (x - mrks[seq].x) + ")"
        , y ,"(" + (y - mrks[seq].y) + ")"
        );
    }
    
    function onInit() {
      A5.set();
      SPI1.setup({sck:B3, miso:B4, mosi:B5, baud: 1000000});
                       // spi, dc, cs, rst, callback
      dsp = dMod.connect(SPI1, B7, B6, A8, function() {
          dsp.clear();
          // print markers like dice face of 5
          mrks.forEach(function(m) {
            mrkr(dsp, m.x, m.y, mSiz, m.xOff, m.yOff); });
          // setup touchscreen with callback averaging
          // x and y sequence for calibration of 
          // touchscreen to lcd display.
          SPI2.setup({sck:B13, miso:B14, mosi:B15, baud: 2000000});
          var seq = 0, xs = [], ys = [], x, y;
          touch = tMod.connect(
                // spi, cs, irq, offsetx, offsety, w, h, callback // landscape
                SPI2, B10, B1,   -15,   6, dH, dW, function(yt, xt) {  // portrait
              if (yt !== undefined) {
                // collect x and y for averaging
                xs.push(dW - xt); ys.push(yt);
              } else {
                // log x and y avarages in console 
                logAverage(seq, xs, ys);
                xs = []; ys = []; seq   = (seq +1) % 5;
              }
          });
      });
    }
    
    onInit();
    

    The issues are:

    • ILI9341 initializes in portrait with x=0..239 - 240 pixels wide - and y=0...319 - 320 pixels high - and 0 / 0 top left (see shot).

    • XPT2046 controller is wired portrait, but not in a twisted way... not just rotated by 90 degrees... It could be fixed with the some additional calculation: with or hight - coordinate touch value.

    • it is not good enough to have an x and y offset for the controller function to calculate the actual x and y for a given display size. The offset helps with the touch screen not aligning with the display, but it messes up the scaling: if the low value is ok, the high value is too much off and vice versa. This can be seen in the output generated by above code when touching the calibration points from top left to bottom right.

    Because many touch screens are larger than the display because they show fixed, printed buttons in the overhang area. For touching in the overhang, proper calculation returns values beyond the screen coordinates.

    Produced output (aligned and with headings added):

     1v86 Copyright 2016 G.Williams
    >echo(0);
    =undefined
            expected x / y   effective (deviation)
    1 topLeft       20  20      21 (  1)  21 (  1)
    2 topRight     220  20     201 (-19)  22 (  2)
    3 center       120 160     110 (-10) 144 (-16)
    4 bottomLeft    20 300      19 ( -1) 271 (-29)
    5 bottomRight  220 300     203 (-17) 268 (-32)
    > 
    

    Looking at x coordinate, the low value is about correct, but the deviation for higher values goes linearly up by about 10 per 120 pixels (half screen width). The 'balconies' or 'porches'
    (screen vs display sizes and alignments) impact the calculation beyond what an offset can handle.

    Same can be said for the y coordinate: after adjusting with an offset, the error is even worse.

    Since the issues are hardware - wiring, size and alignment dependent, a module has to provide an option to pass a calculation function that takes minimum AND maximum touch values into account to scale properly with the display size. I'll take a stab at it and will publish in a next post.


    2 Attachments

  • Here it is, the calibration, resulting in a new module and a calibration function:

    // TFT24TRCportraitCalibr2.js
    //
    //  2.4" 240x320 262K Color TFT LCD ILI9341 on SPI1 with 
    //  Resistive Touch Screen Controller XPT2046 on SPI2
    //  using out of box ILI9341 and ADS7843 modules.
    //
    // Wiring:
    //  2.4"
    //  DSP                  PICO [<---USB
    //   1   VCC      red     3   3.3            shared
    //   2   GND      blk     1   GND            shared
    //   3   CS       blu     7   B6   CS        LCD
    //   4   RST      brn     9   A8   reset RST LCD
    //   5   D/C      grn     8   B7   D/C       LCD
    //   6   MOSI     ylw     6   B5   SPI1 MOSI LCD
    //   7   SCK      wht     4   B3   SPI1 SCK  LCD
    //   8   LED      org    18   A5   LED       LCD
    //   9   MISO     grn     5   B4   SPI1 MISO LCD
    //  10   T_CLK    wht    23   B13  SPI2 SCK  Touch
    //  11   T_CS     ylw    22   B10  CS        Touch
    //  12   T_MOSI   grn    25   B15  SPI2 MOSI Touch
    //  13   T_MISO   blu    24   B14  SPI2 MISO Touch
    //  14   T_IRQ    blk    21   B1   IRQ       Touch
    
    var dW = 240, dH = 320, dsp, dMod = require("ILI9341"),
        tSPI=SPI2, tCs = B10, tIrq = B1, 
        touch, tMod = // require("ADS7843");
    // future XPT2046 touchscreen controller
    // default calculation is a pass thru
    { calc: function(x, y, d) { return [x,y,d]; } // default calculation
    , connect: function(spi, cs, irq, callback, calc) {
        // overwrite default 'calculation': pass thru incl. raw values
        if (calc) { this.calc = calc; }
        // wake the controller up
        spi.send([0x90,0],cs);
        // look for a press
        var watchFunction = function() {
          var interval = setInterval(function () {
            if (!digitalRead(irq)) { // touch down
              var d = spi.send([0x90,0,0xD0,0,0], cs);
              callback.apply(undefined, this.calc(d[1]*256+d[2], d[3]*256+d[4], d));
            } else {
              callback();
              clearInterval(interval);
              interval = undefined;
              setWatch(watchFunction, irq, { repeat : false, edge: "falling" });
            }
          }.bind(this), 50);
        }.bind(this);
        setWatch(watchFunction, irq, { repeat : false, edge: "falling" });
        return this;
      }
    };
    
    // marker specs (lik dice face 5; top left to bottom right)
    var mrks =
        [{i:1, label:"topLeft    ", x: 20, y: 20, xOff: 14, yOff:-6}
        ,{i:2, label:"topRight   ", x:220, y: 20, xOff:-66, yOff:-6}
        ,{i:3, label:"center     ", x:120, y:160, xOff:-29, yOff:14}
        ,{i:4, label:"bottomLeft ", x: 20, y:300, xOff: 14, yOff:-6}
        ,{i:5, label:"bottomRight", x:220, y:300, xOff:-74, yOff:-6}
        ];
    var mSiz = 9; // half of marker size, (0.7 of font size)
    
    // print marker at x/y of size s with x/y label
    function mrkr(d,x,y,s,xOff,yOff) {
      dsp.setColor(1,1,1);
      dsp.drawRect(x-s,y-s,x+s,y+s);
      dsp.drawLine(x-s,y,x+s,y);
      dsp.drawLine(x,y-s,x,y+s);
      dsp.setFontVector(s / 0.7);
      dsp.drawString(x + " / " + y, x+xOff, y+yOff);
    }
    
    function average(arry) { // return avarage of array values
      return arry.reduce(
        function(p,c) { return p + c; },0) / arry.length; }
    
    function fInt(i,l) { return ("        " + i).substr(-l); }
    
    function logXY(m,xp,yp,l,d) {
      console.log(
          m.i
        , m.label
        , fInt(m.x,4), fInt(m.y,4)
        , fInt(m[xp],l), (d) ? "(" + fInt(m[xp] - m.x,4) + ")" : ""
        , fInt(m[yp],l), (d) ? "(" + fInt(m[yp] - m.y,4) + ")" : ""
        );
    }
    
    function handleAverage(seq,xs,ys) { // log x / y average
      var m = mrks[seq],
          x = Math.round(average(xs)), 
          y = Math.round(average(ys));
      m.xAvg = x; m.yAvg = y;
      logXY(m,"xAvg","yAvg",6);
      if (seq === 4) { // all in, calc calibration parms and calib with new calc function
        var xscs = [], // xscales = x deltas per pixel
            yscs = [], // yscales = y deltas per pixel
            xoss = [], // xoffsets 
            yoss = []; // yoffsets
        xscs.push((mrks[1].xAvg - mrks[0].xAvg) / (mrks[1].x - mrks[0].x)); // top x deltas
        xscs.push((mrks[2].xAvg - mrks[0].xAvg) / (mrks[2].x - mrks[0].x)); // top left - cent
        xscs.push((mrks[1].xAvg - mrks[2].xAvg) / (mrks[1].x - mrks[2].x)); // cent - top right
        xscs.push((mrks[4].xAvg - mrks[3].xAvg) / (mrks[4].x - mrks[3].x)); // bottom x deltas
        xscs.push((mrks[2].xAvg - mrks[3].xAvg) / (mrks[2].x - mrks[3].x)); // bot left - cent
        xscs.push((mrks[4].xAvg - mrks[2].xAvg) / (mrks[4].x - mrks[2].x)); // cent - top right
        console.log(xscs);
        yscs.push((mrks[3].yAvg - mrks[0].yAvg) / (mrks[3].y - mrks[0].y)); // left y deltas
        yscs.push((mrks[2].yAvg - mrks[0].yAvg) / (mrks[2].y - mrks[0].y)); // top left - cent
        yscs.push((mrks[3].yAvg - mrks[2].yAvg) / (mrks[3].y - mrks[2].y)); // cent - left bottom
        yscs.push((mrks[4].yAvg - mrks[1].yAvg) / (mrks[4].y - mrks[1].y)); // right y deltas
        yscs.push((mrks[2].yAvg - mrks[1].yAvg) / (mrks[2].y - mrks[1].y)); // top right - cent
        yscs.push((mrks[4].yAvg - mrks[2].yAvg) / (mrks[4].y - mrks[2].y)); // cent - bot right
        console.log(yscs);
        var xsc = average(xscs), 
            ysc = average(yscs);
        mrks.forEach(function(m) { 
            xoss.push(m.x - m.xAvg / xsc); 
            yoss.push(m.y - m.yAvg / ysc);
        });
        console.log(xoss);
        console.log(yoss);
        var xos = average(xoss), 
            yos = average(yoss);
        console.log("x / y scale", xsc, ysc);
        console.log("x / y offset", xos, yos);
        mrks.forEach(function(m){
          m.xc = Math.round((m.xAvg / xsc) + xos);
          m.yc = Math.round((m.yAvg / ysc) + yos);
          logXY(m,"xc","yc",4,true);
        });
        
        // calibrated calc function set in touch:
        // x / y scale   -121.5825         89.79285714285
        // x / y offset   258.33405300927 -18.53090446265
        touch.calc = function(yr, xr) { // xy raw
          return [Math.round(xr / xsc + xos) // / x scale per pixel + x offset
                 ,Math.round(yr / ysc + yos) // / y scale per pixel + y offset
                 ];
        };
        
        calibrated = true;
        console.log("---- calibrated, normal mode");
        console.log(" touch markers for validation.");
      }
    }
    
    var calibrated = false;
    
    function onInit() {
      A5.set();
      SPI1.setup({sck:B3, miso:B4, mosi:B5, baud: 1000000});
                       // spi, dc, cs, rst, callback
      dsp = dMod.connect(SPI1, B7, B6, A8, function() {
          dsp.clear();
          // print markers like dice face of 5
          mrks.forEach(function(m) {
            mrkr(dsp, m.x, m.y, mSiz, m.xOff, m.yOff); });
          console.log("---- in calibration mode:");
          console.log(" touch markers from top left to bottom right.");
          // setup touchscreen with callback averaging
          // x and y sequence for calibration of 
          // touchscreen to lcd display.
          SPI2.setup({sck:B13, miso:B14, mosi:B15, baud: 2000000});
          var seq = 0, xs = [], ys = [], x, y;
          touch = tMod.connect(
              // spi, cs, irq, callback, calc // landscape
              SPI2, B10, B1, function(m1, m2, rd) {  // portrait
                var xt, yt;
                if (calibrated) { // calibrated mode
                  xt = m1; yt = m2;
                  if (xt !== undefined) {
                    console.log(fInt(xt,4),fInt(yt,4));
                  }
                } else { // calibration mode
                  xt = m2; yt = m1;
                  if (xt !== undefined) {
                    // console.log(rd);
                    // collect x and y for averaging
                    xs.push(xt); ys.push(yt);
                  } else {
                    // log x and y avarages in console 
                    handleAverage(seq, xs, ys);
                    xs = []; ys = []; seq   = (seq +1) % 5;
                  }
                }
          });
      });
    }
    
    onInit();
    

    Related console output:

     1v86 Copyright 2016 G.Williams
    >echo(0);
    =undefined
    ---- in calibration mode:
     touch markers from top left to bottom right.
    1 topLeft       20   20  29148    3490
    2 topRight     220   20   4862    3495
    3 center       120  160  17118   16160
    4 bottomLeft    20  300  28996   28347
    5 bottomRight  220  300   4706   28424
    [ -121.43, -120.3, -122.56, -121.45, -118.78, -124.12 ]
    [ 88.775, 90.5, 87.05, 89.03214285714, 90.46428571428, 87.6 ]
    [ 260.01976284584, 260.03623188405, 260.95849802371, 258.76811594202, 258.75164690382 ]
    [ -19.25601574739, -19.31225645763, -21.76997549511, -18.85108263367, -19.71718957136 ]
    x / y scale -121.44 88.90357142857
    x / y offset 259.70685111989 -19.78130398103
    1 topLeft       20   20   20 (   0)   19 (  -1)
    2 topRight     220   20  220 (   0)   20 (   0)
    3 center       120  160  119 (  -1)  162 (   2)
    4 bottomLeft    20  300   21 (   1)  299 (  -1)
    5 bottomRight  220  300  221 (   1)  300 (   0)
    ---- calibrated, normal mode
     touch markers for validation.
      21  18
      23  17
      18  18
     222  19
     221  19
     223  20
     120 160
     121 160
     116 160
     121 159
      19 303
      20 303
      16 299
     220 304
     221 301
     221 299
     222 301
    > 
    

    The calibration goes as follows:

    • 30..53 provided a new module base on existing one that allows to set a customized calculation function
      - 30 shows the default - pass through function - which accepts the raw coordinates and the read data. Read data is pass just in case...
      - 41 shows the calculation invocation with the pre-calculation of the raw coordinates (same as known from existing modules: highByte * 256 + lowByte)
      - 48 and 49 are noteworthy where context of module / touch singleton is bound in order to use this.calc(...) function in nested anonymous watch and interval functions.
      - 176..187 raw values are collected while touching the calibration marks from top left to bottom right.
      - 97 starts the actual calibration calculations...
      - 98..117 calculates raw value per pixel based on known coordinates of the markers and measured values: scale value (raw value) / pixel = read value difference divided by pixel delta of the markers
      - 118..128 calculates the offset for each axis.
      - 126 and 127 show the calculated scale and offset values.
      - 128..132 calculates the new values from the initially read values (1..5 console output) with given scaling and offset and shows them in the console for verification (117..121 console output)
      - 134..141 sets the new calibrated calculation function in touch singleton
      - 143 switches into regular mode for verification of the calc function (touching/tapping the markers again shows new calculated values as expected.

    1 Attachment

  • XPT2046.js module code:

    /*
    
    XPT2046 (pin/function compatible to ADS7843) 
    Resistive Touch Screen Controller module
    
    ` ` `
    var touch, touchModule = require("XPT2046");
    
    function onInit() {
          // ...
          // setup touchscreen 
          SPI2.setup({sck:B13, miso:B14, mosi:B15, baud: 2000000});
          touch = tMod.connect(
              // spi, cs, irq, callback, calc // landscape
              SPI2, B10, B1, function(x, y, rd) {  // portrait
                  if (x !== undefined) {
                    console.log(x,y);
                  }
          }, function(yr, xr, d) { // calc function - converts raw data to x / y coordinates;
            // scale and offset values calculated using markers and default calc function.
            // see http://forum.espruino.com/conversations/292641 - Touchscreen     
    //      return [ Math.round(xr / xsc + xos) // / x scale per pixel + x offset
    //             , Math.round(yr / ysc + yos) // / y scale per pixel + y offset
            return [ Math.round(xr / -121.44          + 259.70685111989) 
                   , Math.round(yr /   88.90357142857 + -19.78130398103)
                   ];
          });
          // ...
    }
    ` ` `
    
     */
    
    exports = // XPT2046 module
    { calc: function(x, y, d) { return [x,y,d]; } // default calculation
    , connect: function(spi, cs, irq, callback, calc) {
        // overwrite default 'calculation': pass thru incl. raw values
        if (calc) { this.calc = calc; }
        // wake the controller up
        spi.send([0x90,0],cs);
        // look for a press
        var watchFunction = function() {
          var interval = setInterval(function () {
            if (!digitalRead(irq)) { // touch down
              var d = spi.send([0x90,0,0xD0,0,0], cs);
              callback.apply(undefined, this.calc(d[1]*256+d[2], d[3]*256+d[4], d));
            } else {
              callback();
              clearInterval(interval);
              interval = undefined;
              setWatch(watchFunction, irq, { repeat : false, edge: "falling" });
            }
          }.bind(this), 50);
        }.bind(this);
        setWatch(watchFunction, irq, { repeat : false, edge: "falling" });
        return this;
      }
    };
    

    Application using the (minified) module code from local Web IDE sandbox/modules folder. Note the touchscreen module .connect() that is supplied with the calculation function to converts the raw screen controller data into x and y for the screen.

    // TFT24TRCportraitCalibr3.js - XPT2046 module test
    //
    //  2.4" 240x320 262K Color TFT LCD ILI9341 on SPI1 with 
    //  Resistive Touch Screen Controller XPT2046 on SPI2
    //  using out of box ILI9341 and ADS7843 modules.
    //
    // Wiring:
    //  2.4"
    //  DSP                  PICO [<---USB
    //   1   VCC      red     3   3.3            shared
    //   2   GND      blk     1   GND            shared
    //   3   CS       blu     7   B6   CS        LCD
    //   4   RST      brn     9   A8   reset RST LCD
    //   5   D/C      grn     8   B7   D/C       LCD
    //   6   MOSI     ylw     6   B5   SPI1 MOSI LCD
    //   7   SCK      wht     4   B3   SPI1 SCK  LCD
    //   8   LED      org    18   A5   LED       LCD
    //   9   MISO     grn     5   B4   SPI1 MISO LCD
    //  10   T_CLK    wht    23   B13  SPI2 SCK  Touch
    //  11   T_CS     ylw    22   B10  CS        Touch
    //  12   T_MOSI   grn    25   B15  SPI2 MOSI Touch
    //  13   T_MISO   blu    24   B14  SPI2 MISO Touch
    //  14   T_IRQ    blk    21   B1   IRQ       Touch
    
    var dW = 240, dH = 320, dsp, dMod = require("ILI9341"),
        touch, tMod = require("XPT2046");
    
    // marker specs (lik dice face 5; top left to bottom right)
    var mrks =
        [{i:1, label:"topLeft    ", x: 20, y: 20, xOff: 14, yOff:-6}
        ,{i:2, label:"topRight   ", x:220, y: 20, xOff:-66, yOff:-6}
        ,{i:3, label:"center     ", x:120, y:160, xOff:-29, yOff:14}
        ,{i:4, label:"bottomLeft ", x: 20, y:300, xOff: 14, yOff:-6}
        ,{i:5, label:"bottomRight", x:220, y:300, xOff:-74, yOff:-6}
        ];
    var mSiz = 9; // half of marker size, (0.7 of font size)
    
    // print marker at x/y of size s with x/y label
    function mrkr(d,x,y,s,xOff,yOff) {
      dsp.setColor(1,1,1);
      dsp.drawRect(x-s,y-s,x+s,y+s);
      dsp.drawLine(x-s,y,x+s,y);
      dsp.drawLine(x,y-s,x,y+s);
      dsp.setFontVector(s / 0.7);
      dsp.drawString(x + " / " + y, x+xOff, y+yOff);
    }
    
    function fInt(i,l) { return ("        " + i).substr(-l); }
    
    function onInit() {
      A5.set();
      SPI1.setup({sck:B3, miso:B4, mosi:B5, baud: 1000000});
                       // spi, dc, cs, rst, callback
      dsp = dMod.connect(SPI1, B7, B6, A8, function() {
          dsp.clear();
          // print markers like dice face of 5
          mrks.forEach(function(m) {
            mrkr(dsp, m.x, m.y, mSiz, m.xOff, m.yOff); });
          // setup touchscreen 
          SPI2.setup({sck:B13, miso:B14, mosi:B15, baud: 2000000});
          touch = tMod.connect(
              // spi, cs, irq, callback, calc
              SPI2, B10, B1, function(x, y) {
                if (x !== undefined) {
                  console.log(fInt(x,4),fInt(y,4));
                }
              }, function(yr, xr, d) {
                // calc function - converts raw data to x / y coordinates;
                // scale and offset values calculated using calibration 
                // markers and default calc function. For more details see
                // http://forum.espruino.com/conversations/292641 - Touchscreen
    //          return [ Math.round(xr / xsc + xos) // / x scale per pixel + x offset
    //                 , Math.round(yr / ysc + yos) // / y scale per pixel + y offset
                return [ Math.round(xr / -121.44          + 259.70685111989) 
                       , Math.round(yr /   88.90357142857 + -19.78130398103)
                       ];
          });
      });
    }
    
    onInit();
    

    Related console output (tapping on markers on screen).

    NOTE the last 4 lines which lay outside of the display, because the touch screen has a pretty sizable porch at the bottom.

     1v86 Copyright 2016 G.Williams
    >echo(0);
    =undefined
      21   18
      22   19
      22   18
     223   20
     222   19
     121  162
     118  160
     121  162
      18  303
      19  303
      17  301
     219  303
     219  300
     220  300
     220  302
     130  333
     127  324
     128  328
     126  324
    > 
    

    Note: This module is used in Modular and extensible UI framework and ui elements conversation.


    1 Attachment

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Touchscreen

Posted by Avatar for allObjects @allObjects

Actions