2014-11-05 248 views
1

虽然想要自定义Google DataVisualization,但我想参数化控件的构造函数,但由于某种原因,当我将inputDataTable作为参数传递时,它似乎不起作用。Websharper/Web.Control构造函数问题

这里是我使用默认的数据:

module Example = 
    let headers = [|"Country"; "Population (mil)"; "Area (km2)" |] 
    let inputDataTable = [| 
    [|box "CN"; box 1234000; box 9640821|] 
    [|box "IN"; box 1133000; box 3287263|] 
    [|box "US"; box 304000; box 9629091|] 
    [|box "ID"; box 232000; box 1904569|] 
    [|box "BR"; box 187000; box 8514877|] 
    |] 

的代码来生成网页上的图表。

let GeoChart headers inputDataTable = 
    Div [] 
    |>! OnAfterRender (fun container -> 
      let dataFormatter = DefaultOptions.NumberFormatter "" 
      let options = DefaultOptions.GeoChart 
      let visualization = new GeoChart(container.Dom) 
      let data = Data.GeoMapData headers inputDataTable 
      dataFormatter.format(data, 1) 
      visualization.draw(data, options) 
     ) 

“预期”控件。

type GoogleGeoChartViewer(headers, inputDataTable) = 
    inherit Web.Control() 

    [<JavaScript>] 
    override this.Body = 
    Google.Charts.GeoChart headers inputDataTable :> _ 

并使用基本模板进行测试。

let HomePage = 
    let headers = Google.Example.headers 
    let inputDataTable = Google.Example.inputDataTable 
    Skin.WithTemplate "HomePage" <| fun ctx -> 
     [ 
      Div [Text "HOME"] 
      Div [new Controls.EntryPoint()] 
      Div [new Controls.GoogleGeoChartViewer(headers, inputDataTable)] 
      Links ctx 
     ] 

但是,当我使用此代码时:地图不会显示。

但是,如果我从参数列表中删除inputDataTable和使用:

let GeoChart headers = 
    Div [] 
    |>! OnAfterRender (fun container -> 
      let dataFormatter = DefaultOptions.NumberFormatter "" 
      let options = DefaultOptions.GeoChart 
      let visualization = new GeoChart(container.Dom) 
      let inputDataTable = Example.inputDataTable 
      let data = Data.GeoMapData headers inputDataTable 
      dataFormatter.format(data, 1) 
      visualization.draw(data, options) 
     ) 

它的工作原理...

headers数组不但是造成任何问题。

会有人知道发生了什么吗?

谢谢你的见解。

回答

1

会发生什么情况是,传递给Web.Control的构造函数的值是在服务器端构建页面期间被序列化为JSON的服务器端值。但是,obj类型没有串行器,所以inputDataTableobj[][]类型)的序列化失败。相反,在工作的版本中,inputDataTable在客户端上构建,因此不需要序列化。

如果inputDataTable确实需要来自服务器端,那么您需要使用可序列化的类型。我不知道究竟如何填写您的数据对象在GeoMapData功能,但解决的办法可能是定义inputDataTable如下:

let inputDataTable = [| 
    ("CN", 1234000, 9640821) 
    ("IN", 1133000, 3287263) 
    ("US", 304000, 9629091) 
    ("ID", 232000, 1904569) 
    ("BR", 187000, 8514877) 
    |] 

,然后在客户端,这样做:

let data = new Base.DataTable() 
data.addRows(inputDataTable) |> ignore 

诀窍是WebSharper表示在客户端使用JavaScript数组的元组。而方法addRows,通常需要obj[][],也有一个过载,需要'T[]。这使您可以编写上述正确类型的F#代码,并将其编译为完全相同的JavaScript代码,就像您传递obj[][]一样。这个技巧用于this example(155行)。

+0

谢谢你的解释。我想要有一个通用函数,以便我可以在地图中添加尽可能多的系列(不是专门用于地理图表,而是用于其他强度函数),这就是为什么我使用obj [ ] []而不是更直接的(string * double ...)[]。我会确保我不使用obj来绕过它。 – user1251614 2014-11-06 06:04:00