My goal is to be able to generate data for a Google Visualizations on the server, and then pass it to the client as java script so that it can be rendered as a line chart. My example below compiles correctly, but produces an error when rendered in a browser. What do I need to do to get the DataCommon object to render correctly as java script, after it has been built on the server?
namespace Website
open System
type Action =
| Test
module Page =
open System.Web
open IntelliFactory.WebSharper.Sitelets
open IntelliFactory.WebSharper.Html
let Page title body : Content<Action> =
PageContent (fun context ->
{ Page.Default with
Title = Some(title)
Body = body context
})
module Chart =
open System
open IntelliFactory.WebSharper
open IntelliFactory.WebSharper.Html
open IntelliFactory.WebSharper.Google
open IntelliFactory.WebSharper.Google.Visualization
open IntelliFactory.WebSharper.Google.Visualization.Base
open IntelliFactory.WebSharper.EcmaScript
open IntelliFactory.WebSharper.Web
let RandomData () =
let random = new Random()
let valueCount = 100
let maxValue = 300
let seriesCount = random.Next(5)
let data = new Base.DataTable()
data.addRows(valueCount)
|> ignore
let addSeries index =
let name = sprintf "Series %d" index
data.addColumn(ColumnType.NumberType, name)
|> ignore
Seq.init valueCount (fun index -> random.Next(maxValue))
|> Seq.iteri (fun valueIndex value -> data.setValue(index, valueIndex, value) |> ignore)
[0 .. seriesCount]
|> List.iter addSeries
data
type LineChart( data : DataCommon, title ) =
inherit Web.Control()
[<JavaScript>]
override this.Body =
let div =
Div []
|>! OnAfterRender (fun container ->
let visualization = new Visualizations.LineChart(container.Dom)
let options = {
Visualizations.LineChartOptions.Default with
width = 400.0
height = 240.0
legend = Visualizations.LegendPosition.Bottom
title = title
}
visualization.draw(data, options))
div :> _
module Site =
open Chart
open Page
open IntelliFactory.Html
open IntelliFactory.WebSharper.Sitelets
let TestPage =
Page "Test" (fun (context : Context<Action>) ->
[
Div [Text "Test"]
Div [new Chart.LineChart(RandomData(), "Test Chart")]
])
let Main =
Sitelet.Sum [
Sitelet.Content "/" Test TestPage
]
open IntelliFactory.WebSharper.Sitelets
type Website() =
interface IWebsite<Action> with
member this.Sitelet = Site.Main
member this.Actions = [Test]
[<assembly: WebsiteAttribute(typeof<Website>)>]
do ()
Your
RandomData
function runs on the server. You are therefore constructing JavaScript-onlyDataTable
objects on the server - the result of doing this is generally undefined.You should:
[<Remote>]
.[<JavaScript>]
.async.Return
from your remote function so as not to block the browser.Check the Remoting page or the relevant section of the manual for more information.
Alternatively, you can pass the data to the constructor of your
Control
object and access it from theBody
member. This will serialize the data during HTML generation and avoid the need for an AJAX call - this is useful for generating static HTML sites, for example.