sps014 / BlazorBindGen

MIT License
16 stars 2 forks source link

Why this is not right? #2

Closed GeorgeS2019 closed 2 years ago

GeorgeS2019 commented 2 years ago

Thx for creating this interesting framework. I was learning through the sample information provided.

I do not get any error and the expected result. Any suggestion?

Source Ref

<body>
    <div id="cy"></div>
</body>

cytoscape.razor


@page "/cytoscape1"

@using BlazorBindGen
@using static BlazorBindGen.BindGen
@inject IJSRuntime runtime

<div id="cy" ></div>

@code
{
    JWindow win;
    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        await Init(runtime);
        win = Window;
        await Draw();
    }

        //var cy = cytoscape({
    //container: document.getElementById('cy'),
    //elements: [
    //  { data: { id: 'a' } },
    //  { data: { id: 'b' } },
    //  {
    //    data: {
    //      id: 'ab',
    //       source: 'a',
    //      target: 'b'
    //    }
    //  }]
    //});
    async Task Draw()
    {
        await Import("https://cytoscape.org/cytoscape.js-tutorial-demo/js/cytoscape.min.js");
        var cyCanvas= win.PropRef("document").CallRef("getElementById", "cy");
        JObjPtr _cy = Window.Construct("cytoscape"); /* js reference to cytoscape */ 
        string elements = @"[
                            { data: { id: 'a' } },
                            { data: { id: 'b' } },
                            {
                              data: {
                                id: 'ab',
                                source: 'a',
                                target: 'b'
                              }
                            }]";
        _cy.SetPropRef("container",cyCanvas); 
        _cy.SetPropVal<string>("elements", elements); 

    }
<style>
    #cy {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0px;
        left: 0px;
    }
</style>

Source for working cytoscape.min.js

cytoscape.min.js

expected result

image

sps014 commented 2 years ago
         var cy=cytoscape(.......); //this is method call, sort of  window.cytoscape(...)
        //this is not contructor and Window.Construct() will create constructor for it which is incorrect

to recreate this call we can use

         //call method and get ptr
    JObjPtr _cy = Window.CallRef("cytoscape",param); /* js reference to cytoscape */ 

Also the parameter to this function need some tweaking

{
  container: document.getElementById('cy'),
  elements: [
    { data: { id: 'a' } },
    { data: { id: 'b' } },
    {
      data: {
        id: 'ab',
        source: 'a',
        target: 'b'
      }
    }]
}

Blazor provides a buitin class called ElementReference to hold a HTML Element so when converting this parameter JS object to C# (autogenerated from JS -> JSON -> C# class. We can replace container with ElementReference

  public class Param
    {
        public ElementReference container { get; set; }
        public List<Element> elements { get; set; }
    }
public class Data
    {
        public string id { get; set; }
        public string source { get; set; }
        public string target { get; set; }
    }

    public class Element
    {
        public Data data { get; set; }
    }

Here is how your code will look like

@page "/"

@using BlazorBindGen
@using static BlazorBindGen.BindGen
@inject IJSRuntime runtime

<div id="cy" @ref="canvas" ></div>

@code
{
    ElementReference canvas;

    JWindow win;
    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        await Init(runtime);
        win = Window;
        await Draw();
    }

    //var cy = cytoscape({
    //container: document.getElementById('cy'),
    //elements: [
    //  { data: { id: 'a' } },
    //  { data: { id: 'b' } },
    //  {
    //    data: {
    //      id: 'ab',
    //       source: 'a',
    //      target: 'b'
    //    }
    //  }]
    //});
    async Task Draw()
    {
        await Import("https://cytoscape.org/cytoscape.js-tutorial-demo/js/cytoscape.min.js");
        //converting param from JS object to C# Class (Convert first to JS->JSON->C# class using automatic generators)
        var param = new Root
            {
                container = canvas,
                elements=new List<Element>
                {
                    new Element{data=new Data{id="a"}},
                    new Element{data=new Data{id="b"}},
                    new Element{data=new Data{id="ab",source="a",target="b"}},
                }
            };
        JObjPtr _cy = Window.CallRef("cytoscape",param); /* js reference to cytoscape */ 
    }

    public class Data
    {
        public string id { get; set; }
        public string source { get; set; }
        public string target { get; set; }
    }

    public class Element
    {
        public Data data { get; set; }
    }

    public class Root
    {
        public ElementReference container { get; set; }
        public List<Element> elements { get; set; }
    }

}
<style>
    #cy {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0px;
        left: 0px;
    }
</style>

Output: result

GeorgeS2019 commented 2 years ago
            <span class="oi oi-list-rich" aria-hidden="true"></span> CryptoScape

This should be <span class="oi oi-list-rich" aria-hidden="true"></span> Cytoscape

Thank you for speedy response with advice!

sps014 commented 2 years ago

@sps014 => I could not get it to display "RED hexagon"?

How to do ==> 'background-color': 'red',

Any suggestion?

HTML Source:


{
          container: document.getElementById('cy'),
          elements: [
            // nodes
            { data: { id: 'a' } },
            { data: { id: 'b' } },
            // edges
            {
              data: {
                id: 'ab',
                source: 'a',
                target: 'b'
              }
            },
          ],
          style: [
            {
              selector: 'node',
              style: {
                shape: 'hexagon',
                'background-color': 'red',
                label: 'data(id)'
              }
            }],
          layout: {
            name: 'grid'
          }
 }

      var param = new Root
          {
              container = canvas,
              elements=new List<Element>
              {
                  new Element{data=new Data{id="a"}},
                  new Element{data=new Data{id="b"}},
                  new Element{data=new Data{id="ab",source="a",target="b"}},
              },
                                style = new List<Style>
                               {
                                     new Style{  selector  ="node";  Style = new StyleElement{  shape="hexagon"; label ="data(id)" }  }
                               }
                              layout = new Layout{ name="grid" }
          };
/// Elements
    public class Element
    {
        public Data data { get; set; }
    }

    public class Data
    {
        public string id { get; set; }
        public string source { get; set; }
        public string target { get; set; }
    }

/// Style
    public class Style
    {
       public string selector  { get; set; }
        public StyleElement style { get; set; }
    }

    public class StyleElement
    {
        public string shape{ get; set; }
        public string label{ get; set; }
    }

/// Layout
    public class Layout
    {
        public string name { get; set; }
    }

    public class Root
    {
        public ElementReference container { get; set; }
        public List<Element> elements { get; set; }
        public List<Style> style{ get; set; }
        public Layout layout { get; set; }
    }
<style>
    #cy {
        width: 400px;
        height: 400px;
        position: relative;
        top: 20px;
        left: 20px;
        border: 3px solid #73AD21;
    }
</style>

image

On higher level you could create a property backgroundColor and annotate it with attribute

 [JsonPropertyName("background-color")]
sps014 commented 2 years ago

on higher level you can print that object and see if correct property names is generated JS side , otherwise it mght be a bug with Cytoscape.

sps014 commented 2 years ago

Can you share your source code , so i can see what you are doing wrong

GeorgeS2019 commented 2 years ago

I think you could use your existing GraphDraw.razor to check the code https://github.com/sps014/BlazorBindGen/blob/main/SampleApp/Pages/GraphDraw.razor

sps014 commented 2 years ago

This is how your object looks like JS side with

        Window["console"].CallVoid("log", param);

Screenshot 2022-08-13 155437

sps014 commented 2 years ago

This might be related to default value of null being passed in some not assigned properties, I would rather assign a valid default value to begin with. look in style[1] background color is assigned to null and for other's as well.

GeorgeS2019 commented 2 years ago

image

GeorgeS2019 commented 2 years ago

Is there a way to specify OptionalVariable so when it is not used, it is ignored?

sps014 commented 2 years ago

Also you were using NewtonSoft.Jsonuse System.Text.Json , your property name would look like

        [JsonPropertyName("background-color")]
GeorgeS2019 commented 2 years ago

Style class in F#

https://github.com/fslaborg/Cyjs.NET/blob/main/src/Cyjs.NET/Style.fs

GeorgeS2019 commented 2 years ago

Found it

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

GeorgeS2019 commented 2 years ago

msedge_lahSYjk5ug

sps014 commented 2 years ago
cy.CallVoid("layout", new { name= "circle"});

Also make ure cy object has a function called layout defined as indicated by these errors

GeorgeS2019 commented 2 years ago

How to format?

cy.CallVoid("style", "node { background-color: cyan; }"); <========work

cy.CallVoid("style", new { node { shape='hexagon'; background-color='blue', label='data(id)'}}); <==not work

sps014 commented 2 years ago

Something like

class container
{
    public Node node{get;set;}
}
class Node
{
    [JsonPropertyName("background-color")]
    public  string backgroundColor{get;set;}
    ///.... etc
}
/*create a new instance of container and use constructor or property set */
cy.CallVoid("style", new container());
sps014 commented 2 years ago
cy.style()
  .fromString('node { background-color: blue; }')

  .update() // update the elements in the graph with the new style
;

Is this possible using your framework??

Yes it is

sps014 commented 2 years ago
cy.CallVoid("style().fromString", "node { background-color: green; }");
cy.CallVoid("update");

Not working, something I have done wrong?

cy.CallRef("style").CallRef("fromString","node {}").CallVoid("update");