Jump to content

Ron

uniGUI Subscriber
  • Posts

    374
  • Joined

  • Last visited

  • Days Won

    31

Posts posted by Ron

  1. By adding these lines you can export the canvas data to the server:

    uses NetEncoding;
    
    procedure TMainForm.UniButton1Click(Sender: TObject);
    begin
      uniSession.AddJS('ajaxRequest(MainForm.form, [''export''], { data: canvas.toDataURL() } );');
    end;
    
    procedure TMainForm.UniFormAjaxEvent(Sender: TComponent; EventName: string;
      Params: TUniStrings);
    var inStream, outStream:TStringStream;
    begin
      if sameText(eventName,'export') then
      begin
        inStream:=TStringStream.Create;
        outStream:=TStringStream.Create;
        inStream.writeString(params.Values['data']);
        inStream.position:=22;
        TNetEncoding.Base64.Decode(inStream, outStream);
        outStream.position:=0;
        uniImage1.Picture.LoadFromStream(outStream);
        uniImage1.Picture.SaveToFile('image.png');
        inStream.Free;
        outStream.Free;
      end;
    end;

     

    Update: moved beginPath and closePath to mouseDown and mouseUp, for more fluid drawing.

    For clearing the canvas use:

    uniSession.AddJS('ctx.clearRect(0, 0, canvas.width, canvas.height);');

     

     

     

    mousemove_ex.zip

    signature.jpg

    • Like 1
    • Thanks 2
  2. Attached is a sample application to give you an idea, for simple freehand drawing, based on this JS in an HTMLFrame:

    <canvas id="mycanvas" width="1200" height="500" style="border:1px solid #000000;">
    <script type="text/javascript">
    
    var canvas = $('#mycanvas')[0];
    var ctx = canvas.getContext("2d");
    var mDown = false; 
    var X, Y, oldX, oldY = 0;
      
    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;
    
    $("#mycanvas").mousemove(function(event){
       event.stopPropagation(); 
       if(mDown){
       coords = canvas.relMouseCoords(event);
       X = coords.x;
       Y = coords.y;
       ctx.moveTo(oldX, oldY);
       ctx.lineTo(X, Y); 
       ctx.stroke();
       oldX = X;
       oldY = Y;
       }	 
    });
    
    $("#mycanvas").mousedown(function(event){
       event.stopPropagation(); 
       if(mDown)return;
       mDown = true;
       coords = canvas.relMouseCoords(event);
       oldX = coords.x;
       oldY = coords.y;
       ctx.strokeStyle = 0;
       ctx.lineWidth =1;
       ctx.lineCap = 'square';
       ctx.beginPath();
      });
    
     $("#mycanvas").mouseup(function(event){
       mDown = false;
       ctx.closePath();   
    });	
    
    </script>

     

    works.jpg

    mousemove.zip

    • Like 1
  3. As long as you do not need mouse move data, you can solve it all in Unigui. Like creating objects and placing them, or creating a line between two points, as you then only need to catch mousedown/up events.

    But if you want to draw freehand lines, then you need mouse move data, which cannot be sent to the server as it is just too much, so it has to be solved in the client using JS.

    Mouse move data is the red line, and if you do not need to cross it, things will be easier.

    • Like 1
  4. I noticed that someone suggested this change on the server side, i.e. replacing hyphen with underscore - not sure if that works:

    if Trim(Request.GetFieldByName('Access_Control_Request_Headers')) <> '' then
      begin
        JustWriteToLog('On WebModuleBeforeDispatch - Trim(Request.GetFieldByName(Access_Control_Request_Headers))');
        Response.SetCustomHeader('Access_Control_Allow_Headers', Request.GetFieldByName('Access_Control_Request_Headers'));
        Handled := True;
      end;

     

  5. Quote

    If we manage to run this service from the local computer, it will be possible to easily take control of external components

    My customers use this function every day, and it is called CORS as mentioned above.
    It is used for triggering receipt printing and cash drawer ejection, and has been working for years.

    The local webserver will only respond if it is opened up for CORS, so make sure it is configured correctly. Then it should work.

    This issue is not something that we are trying to solve, because it is already working in production.
    What I mean is that we know that it works, it only takes the right configuration of the webserver.

  6. Sure, this should work, and you can check the returning data in the event handler before displaying it.

    procedure TMainForm.UniButton1Click(Sender: TObject);
    begin
      UniSession.AddJS('$.get("http://127.0.0.1:8989/GetMi",  function( data ){' +
    	 ' ajaxRequest(MainForm.form, ["test"], { response : data });  '+
       ' }); ');
    end;
    
    procedure TMainForm.UniFormAjaxEvent(Sender: TComponent; EventName: string;
      Params: TUniStrings);
    begin
      if sameText(EventName, 'test') then
        uniEdit1.Text:=Params.Values['response'];
    end;

     

    test1.zip

  7. In my code, I see that I use 127.0.0.1 as local client IP, and the jQuery http client. Three options where the first is a Delphi created Windows service. In all cases the returned data is routed to the server via ajaxRequest. 

    case uniMainModule.comType of
        2: UniSession.AddJS('$.get("http://127.0.0.1:'+uniMainModule.regPort+'?event='+inttostr(EventID)+'&op='+uniMainModule.initials+'", 
        function( data ){' +
    	 ' ajaxRequest(TransForm.form, ["regEvent"], { response : data });  '+
       ' }); ');
        4: UniSession.AddJS('$.get("http://127.0.0.1:'+uniMainModule.regPort+'/regevent.php?event='+inttostr(EventID)+'&op='+uniMainModule.initials+'",   
        function( data ){' +
    	 ' ajaxRequest(TransForm.form, ["regEvent"], { response : data });  '+
       ' }); ');
        5: UniSession.AddJS('$.get("http://127.0.0.1:'+uniMainModule.regPort+'/cgi-bin/regevent.cgi?event='+inttostr(EventID)+'&op='+uniMainModule.initials+'", 
        function( data ){' +
    	 ' ajaxRequest(TransForm.form, ["regEvent"], { response : data });  '+
       ' }); ');
      end;

    For the local server to respond I had to configure it accepting cross-reference calls to a specific folder where the apps called through the server are located:

    <VirtualHost *:80>
        DocumentRoot "c:\apache22\htdocs"
        Header set Access-Control-Allow-Origin "*"
    </VirtualHost>

     

  8. I have an app on the cloud which is communicating with a local webserver, using CORS, cross-origin resource sharing, which requires that the local webserver is configured to accept calls from a client on the same IP. I inject JS code which does an http call to the local webserver, using ajaxRequest to return the reply to the cloud app.

    In theory this is straight-forward, but I had to make three different ways to talk to the local server, all using CORS, to be able to make it work with different customers and their hardware/software setups:

    1. Calling a windows service running an http server, and I prefer this as it is the fastest, but I had to make it call console EXEs to do stuff, to be 100% stable
    2. Calling Apache using PHP, which calls console EXEs
    3. Calling Apache using CGI, which are console apps

    Check your CORS config, as it may block external hosts.

  9. It is working fine with Indy POP3, got over 8000 characters in one message while testing against Google Mail.

    //Message: TListView component set at vsReport
    
    procedure TmainForm.ReadEmails;
    var
      IDmessage: TIdMessage;
      i: Integer;
    
    begin
      try
        with POP3 do
        begin
          AutoLogin := False;
          Host := 'pop.gmail.com';
          Username := '******@gmail.com';
          Password := '*******';
          Port := 995;
          IOHandler := IOHandlerTLS;
          UseTLS := utUseImplicitTLS;
        end;
        with IOHandlerTLS do
        begin
          Destination := 'pop.gmail.com:995';
          Host := 'pop.gmail.com';
          Port := 995;
          DefaultPort := 0;
          SSLOptions.Method:=sslvTLSv1_2;
        end;
        POP3.Connect;
        POP3.Login;
        try
          Messages.Clear;
          IDmessage := TIdMessage.Create(nil);
          try
            //for i := 1 to POP3.CheckMessages do
            for i := 1 to 10 do
            begin
              IDmessage.Clear;
              POP3.Retrieve(i, IDmessage);
              Messages.Items.Add;
              Messages.Items[i - 1].Caption:=DateToStr(IDmessage.Date);
              Messages.Items[i - 1].SubItems.Add(IDmessage.From.Address);
              Messages.Items[i - 1].SubItems.Add(IDmessage.Subject);
              Messages.Items[i - 1].SubItems.Add(IDMessage.Body.Text);
            end;
          finally
            FreeAndNil(IDmessage);
          end;
        finally
          POP3.Disconnect;
        end;
      except
        on e : Exception do
          ShowMessage('error=' + e.Message);
      end;
    end;

     

  10. Quote

    I do not want to change the HTMLFrame size as it is sized automatically via Flex.

     

    The code I presented does not change the HTMLFrame size, but only the canvas size. It makes the canvas fill the HTMLFrame, as the frame resizes.

    The code makes sure your canvas is always filling the frame.

    If you want to know the size of the canvas, you can get it from canvas.height and canvas.width, through an ajax call.

  11. Of course you can add an href tag for identification, but that is not necessary as you have the ability to identify the link through the ajax call using a parameter, as in the example. As you have to use a parameter anyway, you might as well use the parameter itself as the identifier, rather than using the href and then passing the href as a parameter, if you understand what I mean. Keep it simple. You will probably generate the html code automatically, so you can do this the way you like.

    Regarding your issue with the memo, you need to attach a test project for us to be able to analyze what happens.

     

  12. It is very easy to generate an Ajax call from an Anchor element, by using the onclick event:

    <a onclick="ajaxRequest(MainForm.HTMLFrame, ['linkclicked'], {  link: 'test'});">A link</a>
    

    In the MainForm you respond to the call, and open whichever form you wish:

    procedure TMainForm.HTMLFrameAjaxEvent(Sender: TComponent; EventName: string;
      Params: TUniStrings);
    begin
      if sameText(eventname,'linkclicked') then
      begin
        showMessage('Link clicked: '+Params.Values['link']);
      end;
    end;

    A test project is attached.

    ajaxtest.zip

  13. This is the code I use in the HTMLFrame called daycalFrame on MainForm, where I want the canvas to fill the whole frame, making sure redrawing is done on each resize:

    <canvas id="daycal">
    <script type="text/javascript">
    
    var canvas = $('#daycal')[0];
    var ctx = canvas.getContext("2d");
    
    window.addEventListener('resize', resizeCanvas, true);
    function resizeCanvas() {
        canvas.width = MainForm.daycalFrame.getWidth();
        canvas.height = MainForm.daycalFrame.getHeight(); 
        drawStuff();    
    }
      
    </script>  

     

  14. If you are only talking about input, there should be no problem if you use insert queries only.

    Because then you are not opening any tables, but only executing queries.

    If you need to display a lot of data after all the input has been saved, you can join many tables in a query.

    I only use queries, never any table dataset components, and I only use live queries with small tables.

    Better to write the SQL yourself, and select/insert/update only what you need if you need speed.

  15. You can only run protocol commands that the browser is able to interpret, 
    like http/s: and ftp:, or desktop protocol handlers like mailto: and tel:
    as mentioned above, providing the handlers are set up.

    This means you can also do a CORS call to a local web server,
    which then starts a program on the local machine.

    Cross-Origin Resource Sharing (CORS) is a standard that allows
     server to relax the same-origin policy. This is used to explicitly allow
    some cross-origin requests while rejecting others.

    The webserver has to be installed on the local computer,
    of course, and configured to respond to the call. You can
    use Indy HTTP Server to create this webserver.

×
×
  • Create New...