Jump to content

Ron

uniGUI Subscriber
  • Posts

    374
  • Joined

  • Last visited

  • Days Won

    31

Posts posted by Ron

  1. Attached is an example, in MainForm.script you may have:

    function myFunction() {
      var num = 2 + 3;
      ajaxRequest(MainForm.form, ['callback'], { res: num} );
    }

    And in MainForm:

    procedure TMainForm.UniButton1Click(Sender: TObject);
    begin
      uniSession.addJS('myFunction()');
    end;
    
    procedure TMainForm.UniFormAjaxEvent(Sender: TComponent; EventName: string;
      Params: TUniStrings);
    begin
     if sameText(eventname,'callback') then
      begin
        showMessage('Result: '+Params.Values['res']);
      end;
    end;

     

    ajaxtest.zip

    • Like 2
  2. I see, then you could probably use a simple proxy server with only url rewriting capabilities, like EZProxy:

    https://help.oclc.org/Library_Management/EZproxy/Get_started/About_URL_rewriting

    Edit: I did not notice that EZProxy costs money, but there are probably other free proxy servers out there, or you could even build your own using Indy components.

    It is basically two http servers and two clients, feeding data from each server to each client in a cross pattern, being on different ports or IPs.*
    And then just add a url rewrite function, to convert the last part of the url to a parameter format.

  3. Quote

    How could I do it so that when giving the "net stop" it waits for the application to actually finish, and then starts?

    If you have both the start and stop commands in the batch file, as mentioned, it will wait for the service to stop, before it starts it.
    In other words, the "net stop" command is "blocking", and will not return until the service stops, and then the next batch command (net start) is executed..

    If you use the hyperserver, it is of course the webserver service that runs the ISAPI modules that has to be stopped and started, aka restarted.
    I am not sure, however, if this will work from an Unigui app, when I think about it, as you may need administrator privileges.

    In that case, you may have to create a desktop app, which you run as admin at startup, and communicates with the Ungui app, to run the batch file.

  4. I guess you can solve this using hyperserver and aliases in the web server setup, running two separate instances of the app, one in each directory:

    <Directory "C:/myapp1>
        Options FollowSymLinks ExecCGI
        AllowOverride None
        Order allow,deny
        Allow from all
        DirectoryIndex myapp.dll?q=param1
    </Directory>
    Alias /option1 "C:/myapp1"
    
    <Directory "C:/myapp2>
        Options FollowSymLinks ExecCGI
        AllowOverride None
        Order allow,deny
        Allow from all
        DirectoryIndex myapp.dll?q=param2
    </Directory>
    Alias /option2 "C:/myapp2"                                      

    So the URL would be https//mydomain.com/option1 or 2, as the dll is specified as the folder index.

    You may skip using a parameter, by just checking startup directory to determine which alias was used.

    Using a URL Rewrite function in the web server setup is another option, to translate part of a URL to a parameter.

  5. You could have a batch file, e.g. "restart.bat", which restarts the service:

    net stop uniguiService
    net start uniguiService

    The batch file may be executed  in a click event handler, or you could use an incoming email or an SMS from a specific phone number, with a code word in the text, triggering a PHP file on a webserver. Using SMS, you specify which file to run at incoming messages to the the virtual SMS number, at the provider. The following PHP extracts message data from the HTTP Post call from the provider and runs the batch file, this assumes you have a running webserver set up with PHP to handle incoming calls:

    <?php
      $Sid = $_POST['MessageSid'];
      $From = $_POST['From'];
      $To = $_POST['To'];
      $Body = $_POST['Body'];
      
      $From = substr($From,3,8);
      
      if(($From==='12345678')&&(strtolower ($Body)==='restart')){
        $output = shell_exec('c:\restart.bat');
        $message = "Web Server Restart: " . $output;
        $response = '<?xml version="1.0" encoding="UTF-8"?><Response><Message>' . $message . '</Message></Response>';
        echo $response;
      }
    
    ?>

     

  6. If you wake up one day, and suddenly conclude that coding is the work of the devil, you may want to delete all of your contributions.

    There may be a million more reasons to turn away from coding, so who knows the motivation - or lack thereof.

    Some may be addicted to coding, and would do better staying away from it. Especially if it ruins their health.

    Or what if your IQ doubles overnight, and you are suddenly ashamed of your old code, which now looks terrible.

  7. Make sure your image file reference is correct, like <img src="files/myimage.jpg"> if your image is located in /files.

    You can also use the complete URL, like https://mydomain.com/files/myimage.jpg if you run it on a server, or localhost/files/myimage.jpg if running locally.

    Not sure if you have to use UniHTMLFrame for the local references to work, but if you are only serving local files, that should do it.

    If you run the app on a non-standard (non-80) port, then of course the port has to be specified if not using a local reference.

  8. It is possible to access local files (at the client), but not directly due to security reasons.

    Only indirectly, through a server installed on the client computer - it could be a TCP server, FTP or HTTP.

    In such a case, one needs to create and install the server, and make a custom directory listing routine.

    Using HTTP, you can use CORS calls, that is call a local resource from the client, like a webserver on port 80 on localhost/127.0.0.1, using Javascript.

    You can also run the call from the server, but then you have to go through the firewall at the client network.

     

  9. Last update, with one more class to internalize variables, for cleaner code.

    It seems like p5 works pretty well with Unigui. Movable polygons with movable vertices.

    Edit: Using literal object for polygons, for a bit more efficient code.

    Edit 2: Added function for deleting selected polygon.

    Edit 3: Added function for inserting and deleting vertices.

    JS code:

    <div id='cnvCont'></div>
    <script type="text/javascript">
    
    new p5();
    let bgImg;
    let imgLoaded = false;
    const px = 8;
    const minimumVx = 3;
    const vxFillCol = 'white';
    const selVxCol = 'red';
    const vxCol = 'rgb(0,0,0)';
    const hoverPolyCol = 'green';
    const drawPolyCol = 'red';
    const polyCol = 'blue';
    const selPolyCol = 'black';
    const polyStrokeW = 2;
    
    let Vertex = function(ix, iy) {	  
      this.x = ix;
      this.y = iy;
    
      this.drawVx = function(selected) {
        if (selected) {
          stroke(selVxCol);
          strokeWeight(2);
        } else {
          stroke(vxCol);
          strokeWeight(1);
        }	
        fill(vxFillCol);
        rect(this.x-round(px/2), this.y-round(px/2), px);	  
      };
      
      this.move = function(dX, dY) {	  
        this.x += dX;
        this.y += dY;  
      };	
      
      this.hit = function(mX, mY) {
        return (collidePointRect(mX, mY, this.x-px, this.y-px, px*2, px*2));
      };  
    };  
    
    class Polygon {
      constructor(x, y) {
        this.isSelected = false;
        this.closed = false;
        this.hover = false;
        this.moveLock = false;
        this.vxhover = false;
        this.vxMoveLock = false;
        this.vxi = -1;
        this.vx = [];
        this.vx.push(new Vertex(x,y));
      }
      
      addVx(x,y) {
        this.vx.push(new Vertex(x,y));	
      }	 
      
      doClose() {
        this.closed = true;
        this.isSelected = true;
      }	  
      
      move(dX, dY) {
        this.vx.forEach( v => {
          v.x += dX;
          v.y += dY;
        }); 
      }
      
      drawPoly(len, mX, mY) {
        if (this.hover) {
          cursor(MOVE); 
          stroke(hoverPolyCol); 
        } else 
        if (!this.closed)
          stroke(drawPolyCol);	
        else  
          stroke(polyCol);
        if (this.isSelected) stroke(selPolyCol);
        strokeWeight(polyStrokeW);
        noFill();
        if (len>1) 
          this.vx.slice(0, len-1).forEach( (vx, i) => {
            line(vx.x, vx.y, this.vx[i+1].x, this.vx[i+1].y);	  
          });	
        let lastVx = this.vx[len-1], startVx = this.vx[0];	  
        (!this.closed) ?
          line(lastVx.x, lastVx.y, mX, mY) :
          line(lastVx.x, lastVx.y, startVx.x, startVx.y);  
      }	
      
      displayVx(len, mX, mY) {
        this.vxhover = false;	    
        this.vx.forEach((v, i) => {
          v.drawVx(i===this.vxi);
          if (!this.vxMoveLock)
            if (v.hit(mX, mY)) {	  
              this.vxi = i;
              this.vxhover = true;		
            }	
          });
      }	  
      
      moveVx(dX, dY) {
        if (!this.moveLock && (this.vxhover || this.vxMoveLock)) {
          cursor(HAND); 
          if (mouseIsPressed) {
            this.vxMoveLock = true;
            this.vx[this.vxi].move(dX, dY);
          } else 
            this.vxMoveLock = false;
        } else this.vxhover = false;	  
      }	
      
      movePoly(dX, dY) {  
        if (!this.vxMoveLock && (!this.vxhover) && (this.hover || this.moveLock)) {  
          if (mouseIsPressed) {
            this.moveLock = true;	
            this.move(dX, dY);
            this.vxi = -1;
            this.vxhover = false;
          } else 
            this.moveLock = false;	  
        }  
      }	 
      
      delVx() {
        if (this.vxi < 0) return;  
        this.vx.splice(this.vxi, 1);
        this.vxMoveLock = false;
      }  
      
      insertVx() {
        if (this.vxi < 0) return;  
        let vxn = this.vxi - 1;
        if (vxn < 0) vxn = this.vx.length - 1;	
        let ix = (round(this.vx[this.vxi].x + this.vx[vxn].x)/2);
        let iy = (round(this.vx[this.vxi].y + this.vx[vxn].y)/2);
        this.vx.splice(this.vxi, -1, new Vertex(ix,iy));  
      }	
      
      duplicate() {
        if (this.vxi < 0) return;
        let vi = this.vx[this.vxi];
        return this.vx.some( (vx, i) => {
          return (((abs(vx.x-vi.x))<10) && ((abs(vx.y-vi.y))<10) && (i!=this.vxi)); 
        });	
      }	  
      
      display(mX, mY, dX, dY) {
        this.hover = (collidePointPoly(mX, mY, this.vx) && (!polys.vxMoveLocked()) 
          && (!(polys.moveLocked() && !this.isSelected)) && (!polys.drawing()));  
        let len = this.vx.length;
        this.drawPoly(len, mX, mY);
        if (this.isSelected) {
          this.displayVx(len, mX, mY);
          this.movePoly(dX, dY);
          this.moveVx(dX, dY);
        }
      }
    }
    
    let polys = {
      started: false,
      closed: false,
      pArray: [],
      selIndex: -1,
      count: 0,
      
      ready: function() {
        return (!this.started);
      },
      
      drawing: function() {
        return ((this.started)&&(!this.closed));
      },  
      
      moveLocked: function() {
        return this.pArray.some( poly => {
          return (poly.moveLock===true);	
        });	
      },	
      
      vxMoveLocked: function() {
        return this.pArray.some( poly => {
          return (poly.vxMoveLock===true);	
    	});	
      },
      
      clear: function() {
        this.started = false;
        this.closed = false;
        this.pArray = [];   
        this.selIndex = -1;
        this.count = 0;
      },	
      
      newPoly: function(mX, mY) {
        if ((mX<0) || (mY<0) || (mX>bgImg.width) || (mY>bgImg.height)) return;
        this.clearSelected();
        this.pArray.push(new Polygon(mX, mY)); 
        this.started = true;
        this.closed = false;
        this.count = this.pArray.length;
        this.selIndex = this.count - 1;	
      },
      
      addVx: function(mX, mY) {
        if ((mX<0) || (mY<0) || (mX>bgImg.width) || (mY>bgImg.height)) return;
        if (this.pArray.every( (poly, i) => {
          return (poly.hover && (i!=this.selIndex));
        })) return;	
        this.selected().addVx(mX,mY);	
      },
      
      canClose: function(mX, mY) {
        return ((Math.abs(mX-this.getX())<10) && (Math.abs(mY-this.getY())<10)); 
      },
      
      doClose: function() {
        this.selected().doClose();  
        this.started = false;  
        this.closed = true;
      },
      
      delSelected: function() {
        if (this.selIndex < 0) return false;
        if (this.started) {
          this.pArray.pop();
          this.started = false;
        } else
          this.pArray.splice(this.selIndex, 1); 
        this.count = this.pArray.length;	
        this.selIndex = -1;
        return true;
      },	
      
      clearSelected: function() {
        this.pArray.forEach( poly => {
          poly.isSelected = false;
        }); 
        this.selIndex = -1;
      },
      
      doSelect: function() {
        return this.pArray.some( (poly, i) => {
          if (poly.hover || poly.vxhover) {
            this.clearSelected();
        	this.selIndex = i;
        	poly.isSelected = true;  
        	return true;
          }	
        });	
      },
      
      selected: function() {
        if (polys.selIndex>-1) 
          return this.pArray[this.selIndex]; 
      },
      
      isSelected: function() {
        return (polys.selIndex>-1); 
      },  
      
      isEmpty: function() {
        return (this.count===0);  
      },
      
      isClosed: function() {
        return (this.closed);  
      },
      
      vxLen: function() {
        return this.selected().vx.length;  
      },
      
      getVx: function() {
        return this.selected().vx;  
      },
      
      getX: function() {
        return this.selected().vx[0].x; 
      },
      
      getY: function() {
        return this.selected().vx[0].y; 
      },
      
      dupCheck: function() {
        if ((this.count>0) && (this.selIndex>-1))
          return this.selected().duplicate();  
      },
      
      delVxDup: function() {
        if ((this.vxLen() > minimumVx)  && (this.dupCheck()))
          this.selected().delVx();
      },
      
      delVx: function() {
        if (this.vxLen() > minimumVx)
          this.selected().delVx();
      },
      
      hover: function() {
        this.pArray.forEach( poly => {
          if (poly.hover) return true;
        });
      }, 
      
      insertVx: function() {
        this.selected().insertVx(); 
      },	  
      
      display: function(mX, mY, dX, dY) {
        if (this.isEmpty()) return;
        cursor(ARROW);
        this.pArray.forEach( poly => {
          poly.display(mX, mY, dX, dY);
        });   
      }
    }  
    
    function setup() {
      loadImage('files/city.jpg', regImg);
    }
    
    function regImg(img) {
      bgImg = img;
      let cnv = createCanvas(bgImg.width,bgImg.height);
      cnv.parent('cnvCont');
      imgLoaded = true;
    }
    
    function draw() {
      if (imgLoaded) background(bgImg);
      polys.display(mouseX, mouseY, mouseX-pmouseX, mouseY-pmouseY);
    }
    
    function pushData() {
      ajaxRequest(MainForm.HTMLFrame, ['getCoords'], { data : JSON.stringify(polys.getVx()) });	
    }	
    
    function mousePressed() {	
      if (polys.doSelect()) 
        return
      else
      if (polys.ready()) 
        polys.newPoly(mouseX, mouseY);
      else 
      if (polys.drawing()) {
        if (polys.canClose(mouseX, mouseY)) {
          polys.doClose();
          pushData();
        } else polys.addVx(mouseX, mouseY); 
      }	  
    }
    
    function mouseReleased() {
      if (!polys.isClosed()) return;
      polys.delVxDup();
    }
    
    function doubleClicked() {
      if (polys.isEmpty()) return;
      if (polys.isSelected()) polys.insertVx();
    }
    
    function keyPressed() {
      if (polys.isEmpty()) return;
      if ((key = ESCAPE) && (polys.vxLen() > (minimumVx - 1))) {
        polys.doClose();
        pushData();
      } else
      if ((key = ESCAPE) && (polys.vxLen() <= (minimumVx - 1)) && polys.drawing()) 
        polys.delSelected();
    }  
    
    function delVertex() {
      if (polys.isEmpty()) return;
      if (!polys.isClosed()) return;
      polys.delVx();
    }	
    
    function insertVertex() {
      if (polys.isEmpty()) return;
      if (polys.isSelected()) polys.insertVx();
    }
    
    function delSelected() {
      if (polys.isEmpty()) {
        ajaxRequest(MainForm.HTMLFrame, ['delete'], { status : 'no polygons to delete' });		
        return;
      }	  
      if (polys.delSelected())
        ajaxRequest(MainForm.HTMLFrame, ['delete'], { status : 'polygon deleted ok' });		
      else ajaxRequest(MainForm.HTMLFrame, ['delete'], { status : 'no polygon selected' });		
    }	
    
    function resetCnv() {
      polys.clear(); 
    }	
    
    </script>

     

     

     

     

     

     

     

     

     

     

     

    Testprog.zip

    • Thanks 2
  10. Last update, moved some code into an object, so each polygon will do the hit testing itself.

     

    <div id='cnvCont'></div>
    
    <script type="text/javascript">
    
    new p5();
    
    let pStarted, pClosed = false;
    let pArray = [];
    let bg;
    let imgLoaded = false;
    let selP = -1;
    
    class Coords {
      constructor(ix, iy) {
        this.x = ix;
        this.y = iy;
    	this.selected = false;
      }
    }  
    
    class MPoly {
      constructor(x, y) {
        this.selected = false;
        this.closed = false;
        this.hover = false;
        this.vx = [];
        this.vx.push(new Coords(x,y));
        pStarted = true;
        pClosed = false;
      }
      
      addVx(x,y) {
        this.vx.push(new Coords(x,y));	
      }	 
      
      close(doPop) {
        if(doPop)this.vx.pop();
        this.closed = true;
        pClosed = true;
        pStarted = false;  
      }	  
      
      move(dx, dy) {
        for (let i=0;i<this.vx.length;i++) {
          this.vx[i].x += dx;
          this.vx[i].y += dy;
        }  
      }
      
      display() {
        let hit = collidePointPoly(mouseX, mouseY, this.vx);
        if(hit && this.closed) {
          cursor(MOVE); 
          this.hover = true;
        } else 
          this.hover = false;
        if ((mouseIsPressed === true) && hit && this.closed) 
          this.move(mouseX - pmouseX, mouseY - pmouseY);
        if(hit && this.closed) {
          stroke(0, 255, 0);  
        }  
        else if (!this.closed)
          stroke(255, 0, 0);
        else
          stroke(0, 0, 255);
        let len = this.vx.length;
        if (len>1) 
          for(let i=0;i<len-1;i++)      
            line(this.vx[i].x, this.vx[i].y, this.vx[i+1].x, this.vx[i+1].y);
        if (!this.closed) 
          line(this.vx[len-1].x, this.vx[len-1].y, mouseX, mouseY);	
        else 
          line(this.vx[len-1].x, this.vx[len-1].y, this.vx[0].x, this.vx[0].y);
      }
    }
    
    function setup() {
      loadImage('files/city.jpg', regImg);
    }
    
    function regImg(img) {
      bg = img;
      let cnv = createCanvas(bg.width,bg.height);
      cnv.parent('cnvCont');
      strokeWeight(2);
      imgLoaded = true;
    }
    
    function draw() {
      if (imgLoaded) background(bg);
      let len = pArray.length;
      if (len == 0) return;
      cursor(ARROW);
      for(let i=0;i<len;i++)  {
        pArray[i].display();
      } 
    }
    
    function mouseClicked() {
      let len = pArray.length;
      for(let i=0;i<len;i++)  
        if (pArray[i].hover) {
          selP = i;	
          return;
        } 
      if ((pStarted)&&(!pClosed)) 
        pArray[selP].addVx(mouseX, mouseY);
      if (!pStarted) {
        pArray.push(new MPoly(mouseX, mouseY));
        selP = pArray.length - 1;
      }	
      else 
      if ((!pClosed) && ((Math.abs(mouseX-pArray[selP].vx[0].x)<10) && (Math.abs(mouseY-pArray[selP].vx[0].y)<10))) {
        pArray[selP].close(true);
        ajaxRequest(MainForm.HTMLFrame, ['getCoords'], { data : JSON.stringify(pArray[selP].vx) });
      }
    }
    
    function keyPressed() {
      let len = pArray.length;
      if (len == 0) return;
      len = pArray[selP].vx.length;
      if ((key = ESCAPE) && (len > 2)) {
        pArray[selP].close(false);
        ajaxRequest(MainForm.HTMLFrame, ['getCoords'], { data : JSON.stringify(pArray[selP].vx) });
      }
    }  
    
    function resetCnv() {
      pStarted = false;
      pClosed = false;
      pArray = [];  
    }	
    
    </script>

     

     

    Testprog.zip

  11. Attached is another version, using p5.js, from p5js.org

    p5() had to be initiated in on-demand global mode at the beginning, see https://github.com/processing/p5.js/wiki/p5.js-overview

    The canvas is created within a div container, set up via a callback function with loadImage(), and the function draw() runs a continous loop.

    <div id='cnvCont'></div>
    
    <script type="text/javascript">
    
    new p5();
    
    let pStarted, pClosed = false;
    let cArray = [];
    let bg;
    let imgLoaded = false;
    
    class Coords {
      constructor(ix, iy) {
        this.x = ix;
        this.y = iy;
      }
    }  
    
    function setup() {
      loadImage('files/city.jpg', regImg);
    }
    
    function regImg(img) {
      bg = img;
      let cnv = createCanvas(bg.width,bg.height);
      cnv.parent('cnvCont');
      strokeWeight(2);
      imgLoaded = true;
    }
    
    function draw() {
      if (imgLoaded) background(bg);
      if (!pStarted) return;
      if (!pClosed)
        stroke(255, 0, 0);
      else
        stroke(0, 0, 255);
      let len = cArray.length;
      if (len>1) 
        for(i=0;i<len-1;i++)      
          line(cArray[i].x, cArray[i].y, cArray[i+1].x, cArray[i+1].y);
      if (!pClosed) 
        line(cArray[len-1].x, cArray[len-1].y, mouseX, mouseY);	
      else 
        line(cArray[len-1].x, cArray[len-1].y, cArray[0].x, cArray[0].y);
    }
    
    function mouseClicked() {
      if (!pClosed) cArray.push(new Coords(mouseX, mouseY));
      if (!pStarted) 
        pStarted = true;
      else 
      if ((!pClosed) && ((Math.abs(mouseX-cArray[0].x)<10) && (Math.abs(mouseY-cArray[0].y)<10))) {
        cArray.pop();
        pClosed = true;
        ajaxRequest(MainForm.HTMLFrame, ['getCoords'], { data : JSON.stringify(cArray) });
      }
    }
    
    function resetCnv() {
      pStarted = false;
      pClosed = false;
      cArray = [];  
    }	
    
    
    </script>

     

    Testprog.zip

    • Upvote 1
  12. If the function is not defined, it is not loaded.

    Put the script in a textfile and load it, and it will work despite having commented lines. Or terminate those lines.

    Dynamically loading a script as strings in code, including commented lines (starting with //) and not terminating them with CR/LF (chr(13)+chr(10)) will disable everything after the //, and functions will then not be loaded.

    So if it works, it is loaded. If it does not work, it is not loaded.

     

    If part of the script is "lost" due to commented lines, you will not get a warning in the console as that part is not loaded.

    The browser just believes you have disabled the rest of the script. Checking for "undefined" or running the function, will tell you if it is loaded or not.

    'function updateView()'+
          '{'+
          '  //canvas.width = MainForm.HTMLFrame.getWidth();'+  chr(13)+chr(10)+
          '  //canvas.height = MainForm.HTMLFrame.getHeight(); '+   chr(13)+chr(10)+
          '  canvas.width = 600;'+
          '  canvas.height = 360;'+
          '  drawScreen();'+
          '}'+

     

  13. Attached is a test project, using JS to catch and serve the coordinates selected on an image.

    This is the code for the HTMLFrame:

    <canvas id="cnv">
    <script type="text/javascript">
    
    var canvas = $('#cnv')[0];
    var ctx = canvas.getContext("2d");
    var imgMap = new Image();
    var mDown, started, mClosed = false;
    var numPoints = 0;
    var aCoords = [];
    //imgMap.src = "files/city.jpg";  
    
    function relMouseCoords(event){
        var totalOffsetX = 0;
        var totalOffsetY = 0;
        var canvasX = 0;
        var canvasY = 0;
        var currentElement = this;
        do{
            totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
            totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
        }
        while(currentElement = currentElement.offsetParent);
        canvasX = event.pageX - totalOffsetX;
        canvasY = event.pageY - totalOffsetY;
        return {x:canvasX, y:canvasY}
      }
      
    HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
    
    window.addEventListener('resize', updateView, true);
    function updateView() {
      //canvas.width = MainForm.HTMLFrame.getWidth();
      //canvas.height = MainForm.HTMLFrame.getHeight(); 
      canvas.width = 600;
      canvas.height = 360;
      drawScreen();
    }
    
    function resetImg() {
      ctx.beginPath();
      started = false;
      mClosed = false;
      numPoints = 0;
      ctx.drawImage(imgMap, 0, 0, 600, 360); 
      ctx.closePath();
    }
    
    function loadImg() {
      imgMap.src = "files/city.jpg";
      resetImg();
    }  
    
    function drawScreen() {
      ctx.beginPath();
      ctx.drawImage(imgMap, 0, 0, 600, 360); 
      ctx.fillStyle ="#FF0000";
      ctx.lineWidth = 3;
      if(started) {
        ctx.moveTo(aCoords[0].x, aCoords[0].y);
        for(i=1;i<aCoords.length;i++)
          ctx.lineTo(aCoords[i].x, aCoords[i].y);
        if(mClosed){ctx.lineTo(aCoords[0].x, aCoords[0].y)};  
        ctx.stroke();
      }
      ctx.font = "16px Arial";
      ctx.fillText(numPoints, 10,15);
      ctx.closePath();
    }
    
     $("#cnv").mousedown(function(event){
      	if(mDown)return;
    	mDown = true;
       	coords = canvas.relMouseCoords(event);
    	if(!started) {
    	  aCoords = [];
    	  aCoords[0] = coords;
    	  started = true;
    	  mClosed = false;
    	  numPoints = 1;
    	  ctx.strokeStyle ="#FF3333";
    	} else 
    	if (!mClosed) {
    	  if ((Math.abs(coords.x-aCoords[0].x)<10) && (Math.abs(coords.y-aCoords[0].y)<10)) {
           //remove last point, as we close the curve
           numPoints--;
           aCoords.pop();
    	   mClosed = true;
    	   ctx.strokeStyle ="#333333";
           ajaxRequest(MainForm.HTMLFrame, ['getCoords'], { data : JSON.stringify(aCoords) });
    	  } else {
            //add another point
    	    aCoords[numPoints] = coords;
    	    numPoints++;
    	  }
    	  drawScreen();
    	}
    });
    	
     $("#cnv").mouseup(function(event){
      mDown = false;
    });
    	
    $("#cnv").mousemove(function(event){
      event.stopPropagation(); 
      if(mClosed)return;
      if(mDown)return;
      coords = canvas.relMouseCoords(event);	
      if(!mClosed) {
        //update last point as we move around
        aCoords[numPoints] = coords;
        drawScreen();
      }
    });
    
    updateView();
    
    </script>

    At the server side you just grab the coords:

    procedure TMainForm.HTMLFrameAjaxEvent(Sender: TComponent; EventName: string;
      Params: TUniStrings);
    begin
      if sameText(eventName, 'getCoords') then
        uniEdit1.text:=Params.Values['data'];
    end;

     

    Testprog.zip

    test.png

    • Like 1
  14. This can be done in Javascript, using the HTML Canvas object in an HTMLFrame,
    catching mouse down events in the client and pushing the coordinates back to the server, saving the blocks.

    For visual feedback points should be drawn at each click, with lines in between,
    coloring the areas between the points, and for that to work it has to be done in JS.

    Load the image, catch the mouse down coordinates and draw the lines, close the
    area at 4 clicks and run the ajaxevent. Panning and scaling will complicate it a little.

  15. procedure TMainForm.UniButton1Click(Sender: TObject);
    begin
      UniSession.AddJS('function doTest(){ajaxRequest(MainForm.form, ["test"], { data: 58 });};doTest();');
    end;
    
    procedure TMainForm.UniFormAjaxEvent(Sender: TComponent; EventName: string;
      Params: TUniStrings);
    begin
      if EventName = 'test' then
        ShowMessage(Params.Values['data']);
    end;

     

    • Like 1
  16. 13 hours ago, skafy said:

    How did you did it with API?

     

    Due to security reasons the user has to select the files first. Quoting from above source:

    Quote

    Before the HTML5 file API can access a file from the local file system, the user has to select the file to give access to. For security reasons selecting files is done via the <input type="file"> HTML element. Here is an input element example:

     

  17. Use this in your servermodule/customcss:

    @font-face {
      font-family: 'Code128';   
      src: url('files/fonts/Code128.ttf') format('truetype');
      font-weight: normal;
      font-style: normal;
    }


    Put the attached Code128.ttf file in the "fonts" folder which you create under "files", which is under the app dir.

    Install and use the newly added font version for your unilabel, notice that the font name is now without a space.
    I had to remove the space from the font name definition in the ttf file to make this work.

    Also added some other versions of the font if needed. Using them all it would be:

    @font-face {
      font-family: 'Code128';   
      src: url('files/fonts/Code128.ttf') format('truetype'),
       url('files/fonts/Code128.eot') format('embedded-opentype'),
       url('files/fonts/Code128.woff2') format('woff2'),
       url('files/fonts/Code128.svg') format('svg');
      font-weight: normal;
      font-style: normal;
    }

    barcode.jpg

    Code128.ttf

    Code128.woff2 Code128.eot Code128.svg

    • Like 1
  18. When I set the DecimalSeparator property of UniNumberEdit to dot it works during runtime.

    Below is a screenshot with one having the dot and one having the comma, during runtime.
    At design time they both show as comma on my box, but this is maybe due to the locale settings?

     

    dec.jpg

×
×
  • Create New...