[{"data":1,"prerenderedAt":1554},["ShallowReactive",2],{"navigation_docs":3,"-guides-charts":412,"-guides-charts-surround":1549},[4,38,84,326,386],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":37},"Getting started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20,24,28,32],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-book-open",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":6},"Quick start: Nuxt","\u002Fgetting-started\u002Fquick-start-nuxt","1.getting-started\u002F3.quick-start-nuxt",{"title":25,"path":26,"stem":27,"icon":6},"Quick start: plain Vue","\u002Fgetting-started\u002Fquick-start-vue","1.getting-started\u002F4.quick-start-vue",{"title":29,"path":30,"stem":31,"icon":6},"Quick start: React","\u002Fgetting-started\u002Fquick-start-react","1.getting-started\u002F5.quick-start-react",{"title":33,"path":34,"stem":35,"icon":36},"Glossary","\u002Fgetting-started\u002Fglossary","1.getting-started\u002F6.glossary","i-lucide-book-a",false,{"title":39,"icon":40,"path":41,"stem":42,"children":43,"page":37},"Tutorial","i-lucide-graduation-cap","\u002Ftutorial","2.tutorial",[44,49,54,59,64,69,74,79],{"title":45,"path":46,"stem":47,"icon":48},"Tutorial: overview","\u002Ftutorial\u002Foverview","2.tutorial\u002F1.overview","i-lucide-map",{"title":50,"path":51,"stem":52,"icon":53},"Chapter 2: A simple editor","\u002Ftutorial\u002Fsimple-editor","2.tutorial\u002F2.simple-editor","i-lucide-pencil",{"title":55,"path":56,"stem":57,"icon":58},"Chapter 3: Compose features","\u002Ftutorial\u002Fcompose-features","2.tutorial\u002F3.compose-features","i-lucide-blocks",{"title":60,"path":61,"stem":62,"icon":63},"Chapter 4: Your own block, path A","\u002Ftutorial\u002Fown-block-path-a","2.tutorial\u002F4.own-block-path-a","i-lucide-square-plus",{"title":65,"path":66,"stem":67,"icon":68},"Chapter 5: Your own feature, path B","\u002Ftutorial\u002Fown-feature-path-b","2.tutorial\u002F5.own-feature-path-b","i-lucide-puzzle",{"title":70,"path":71,"stem":72,"icon":73},"Chapter 6: Backend and collaboration","\u002Ftutorial\u002Fbackend-and-collaboration","2.tutorial\u002F6.backend-and-collaboration","i-lucide-users",{"title":75,"path":76,"stem":77,"icon":78},"Chapter 7: AI","\u002Ftutorial\u002Fai","2.tutorial\u002F7.ai","i-lucide-sparkles",{"title":80,"path":81,"stem":82,"icon":83},"Chapter 8: The React surface","\u002Ftutorial\u002Freact-surface","2.tutorial\u002F8.react-surface","i-lucide-atom",{"title":85,"icon":14,"path":86,"stem":87,"children":88,"page":37},"Guides","\u002Fguides","3.guides",[89,93,98,103,108,112,116,121,126,130,134,139,144,149,154,159,164,169,174,179,184,189,194,199,204,209,213,218,223,228,233,237,242,247,251,256,261,266,271,276,281,286,291,295,302,307,311,316,321],{"title":90,"path":91,"stem":92,"icon":58},"Feature composition and entries","\u002Fguides\u002Fcomposition","3.guides\u002F1.composition",{"title":94,"path":95,"stem":96,"icon":97},"Media, mentions and transcript features","\u002Fguides\u002Fmedia-mentions-transcript","3.guides\u002F10.media-mentions-transcript","i-lucide-image",{"title":99,"path":100,"stem":101,"icon":102},"Authors and comments","\u002Fguides\u002Fauthors-and-comments","3.guides\u002F11.authors-and-comments","i-lucide-message-square-text",{"title":104,"path":105,"stem":106,"icon":107},"Themes (Obsidian)","\u002Fguides\u002Fthemes","3.guides\u002F12.themes","i-lucide-palette",{"title":109,"path":110,"stem":111,"icon":58},"Composites and the settings UI","\u002Fguides\u002Fcomposites","3.guides\u002F13.composites",{"title":113,"path":114,"stem":115,"icon":78},"AI","\u002Fguides\u002Fai","3.guides\u002F14.ai",{"title":117,"path":118,"stem":119,"icon":120},"Document tree","\u002Fguides\u002Fdocument-tree","3.guides\u002F15.document-tree","i-lucide-folder-tree",{"title":122,"path":123,"stem":124,"icon":125},"Markdown and code","\u002Fguides\u002Fmarkdown-and-code","3.guides\u002F16.markdown-and-code","i-lucide-file-code",{"title":127,"path":128,"stem":129,"icon":83},"Advanced editor in React","\u002Fguides\u002Fadvanced-react","3.guides\u002F17.advanced-react",{"title":131,"path":132,"stem":133,"icon":6},"Kitchen sink: learning path","\u002Fguides\u002Fadvanced-nuxt-example","3.guides\u002F18.advanced-nuxt-example",{"title":135,"path":136,"stem":137,"icon":138},"Production","\u002Fguides\u002Fproduction","3.guides\u002F19.production","i-lucide-server",{"title":140,"path":141,"stem":142,"icon":143},"Register the Nuxt module","\u002Fguides\u002Fnuxt-module","3.guides\u002F2.nuxt-module","i-lucide-package",{"title":145,"path":146,"stem":147,"icon":148},"Storage adapters, comment stores, Nitro host","\u002Fguides\u002Fstorage-adapters","3.guides\u002F20.storage-adapters","i-lucide-database",{"title":150,"path":151,"stem":152,"icon":153},"Migrating from #tiptap-editor","\u002Fguides\u002Fmigration","3.guides\u002F21.migration","i-lucide-arrow-right-left",{"title":155,"path":156,"stem":157,"icon":158},"Content tree mechanics","\u002Fguides\u002Fcontent-tree","3.guides\u002F22.content-tree","i-lucide-git-fork",{"title":160,"path":161,"stem":162,"icon":163},"Block capabilities, abilities and actions","\u002Fguides\u002Fblock-capabilities","3.guides\u002F23.block-capabilities","i-lucide-shield-check",{"title":165,"path":166,"stem":167,"icon":168},"Block types in code and JSON","\u002Fguides\u002Fblock-types","3.guides\u002F24.block-types","i-lucide-shapes",{"title":170,"path":171,"stem":172,"icon":173},"Derive methods and the Derivation index","\u002Fguides\u002Fderive-methods","3.guides\u002F25.derive-methods","i-lucide-git-branch-plus",{"title":175,"path":176,"stem":177,"icon":178},"Block properties and Property definitions","\u002Fguides\u002Fblock-properties","3.guides\u002F26.block-properties","i-lucide-sliders-horizontal",{"title":180,"path":181,"stem":182,"icon":183},"Image studio","\u002Fguides\u002Fimage-studio","3.guides\u002F27.image-studio","i-lucide-image-plus",{"title":185,"path":186,"stem":187,"icon":188},"Prüfung and Freigabestatus","\u002Fguides\u002Fpruefung","3.guides\u002F28.pruefung","i-lucide-stamp",{"title":190,"path":191,"stem":192,"icon":193},"Workspace: find, read, reference and embed Blocks across Documents","\u002Fguides\u002Fworkspace","3.guides\u002F29.workspace","i-lucide-network",{"title":195,"path":196,"stem":197,"icon":198},"EditorPorts: auth and storage","\u002Fguides\u002Feditor-ports","3.guides\u002F3.editor-ports","i-lucide-plug",{"title":200,"path":201,"stem":202,"icon":203},"Collections: an ordered list of Blocks","\u002Fguides\u002Fcollections","3.guides\u002F30.collections","i-lucide-list-checks",{"title":205,"path":206,"stem":207,"icon":208},"Data views: a query shown as table, list or board","\u002Fguides\u002Fdata-views","3.guides\u002F31.data-views","i-lucide-table-properties",{"title":210,"path":211,"stem":212,"icon":193},"Explore: backlinks, related Blocks and the trail","\u002Fguides\u002Fexplore","3.guides\u002F32.explore",{"title":214,"path":215,"stem":216,"icon":217},"Render: export a Block or a Document to a file","\u002Fguides\u002Frender","3.guides\u002F33.render","i-lucide-file-output",{"title":219,"path":220,"stem":221,"icon":222},"Importers: what a dropped file becomes","\u002Fguides\u002Fimporters","3.guides\u002F34.importers","i-lucide-file-input",{"title":224,"path":225,"stem":226,"icon":227},"Templates: start a Document from a Dokumentvorlage","\u002Fguides\u002Ftemplates","3.guides\u002F35.templates","i-lucide-file-stack",{"title":229,"path":230,"stem":231,"icon":232},"Citations","\u002Fguides\u002Fcitations","3.guides\u002F36.citations","i-lucide-quote",{"title":234,"path":235,"stem":236,"icon":163},"AI proposals and the export check","\u002Fguides\u002Fexport-check","3.guides\u002F37.export-check",{"title":238,"path":239,"stem":240,"icon":241},"Query: filter, sort, group and total Blocks","\u002Fguides\u002Fquery","3.guides\u002F38.query","i-lucide-list-filter",{"title":243,"path":244,"stem":245,"icon":246},"Edges: backlinks and authored connections","\u002Fguides\u002Fedges","3.guides\u002F39.edges","i-lucide-link-2",{"title":248,"path":249,"stem":250,"icon":163},"Server routes and authentication","\u002Fguides\u002Froutes-and-auth","3.guides\u002F4.routes-and-auth",{"title":252,"path":253,"stem":254,"icon":255},"Speech: text to audio, and subtitle files","\u002Fguides\u002Fspeech","3.guides\u002F41.speech","i-lucide-audio-lines",{"title":257,"path":258,"stem":259,"icon":260},"Graph: the Edges around a Block","\u002Fguides\u002Fgraph","3.guides\u002F42.graph","i-lucide-waypoints",{"title":262,"path":263,"stem":264,"icon":265},"PDF viewer: passages, anchors and quotes","\u002Fguides\u002Fpdf-viewer","3.guides\u002F43.pdf-viewer","i-lucide-file-search",{"title":267,"path":268,"stem":269,"icon":270},"Obsidian: import and export a vault","\u002Fguides\u002Fobsidian","3.guides\u002F44.obsidian","i-lucide-folder-input",{"title":272,"path":273,"stem":274,"icon":275},"Typst: render a Document as a PDF with citations","\u002Fguides\u002Ftypst","3.guides\u002F45.typst","i-lucide-file-text",{"title":277,"path":278,"stem":279,"icon":280},"Audio: read aloud, mixdown and ElevenLabs","\u002Fguides\u002Faudio","3.guides\u002F46.audio","i-lucide-audio-waveform",{"title":282,"path":283,"stem":284,"icon":285},"Slides: decks, slide layouts and exports","\u002Fguides\u002Fslides","3.guides\u002F47.slides","i-lucide-presentation",{"title":287,"path":288,"stem":289,"icon":290},"Knowledge graph: sources and concepts beside the Documents","\u002Fguides\u002Fknowledge-graph","3.guides\u002F49.knowledge-graph","i-lucide-share-2",{"title":292,"path":293,"stem":294,"icon":78},"AI configuration and secrets","\u002Fguides\u002Fai-configuration","3.guides\u002F5.ai-configuration",{"title":296,"path":297,"stem":298,"children":299,"icon":301},"Index on Postgres: typos, meaning and SQL pushdown","\u002Fguides\u002Findex-pg","3.guides\u002F50.index-pg",[300],{"title":296,"path":297,"stem":298,"icon":301},"i-lucide-database-zap",{"title":303,"path":304,"stem":305,"icon":306},"Charts: bar, line, pie and scatter over a query","\u002Fguides\u002Fcharts","3.guides\u002F51.charts","i-lucide-chart-column",{"title":308,"path":309,"stem":310,"icon":73},"Collaboration on the client","\u002Fguides\u002Fcollaboration","3.guides\u002F6.collaboration",{"title":312,"path":313,"stem":314,"icon":315},"Block UI (drag handle, hover actions)","\u002Fguides\u002Fblock-ui","3.guides\u002F7.block-ui","i-lucide-grip-vertical",{"title":317,"path":318,"stem":319,"icon":320},"Settings and app lifetime","\u002Fguides\u002Fsettings","3.guides\u002F8.settings","i-lucide-settings",{"title":322,"path":323,"stem":324,"icon":325},"Language","\u002Fguides\u002Flanguage","3.guides\u002F9.language","i-lucide-languages",{"title":327,"icon":14,"path":328,"stem":329,"children":330,"page":37},"Reference","\u002Freference","4.reference",[331,335,339,344,348,352,356,360,364,368,373,378,382],{"title":332,"path":333,"stem":334,"icon":143},"Public exports","\u002Freference\u002Fexports","4.reference\u002F1.exports",{"title":336,"path":337,"stem":338,"icon":173},"Derive method contract","\u002Freference\u002Fderive-methods","4.reference\u002F10.derive-methods",{"title":340,"path":341,"stem":342,"icon":343},"Changelog","\u002Freference\u002Fchangelog","4.reference\u002F11.changelog","i-lucide-history",{"title":345,"path":346,"stem":347,"icon":217},"Renderer port","\u002Freference\u002Frenderer-port","4.reference\u002F12.renderer-port",{"title":349,"path":350,"stem":351,"icon":255},"Speech port","\u002Freference\u002Fspeech-port","4.reference\u002F13.speech-port",{"title":353,"path":354,"stem":355,"icon":58},"Presets and features","\u002Freference\u002Fpresets-and-features","4.reference\u002F2.presets-and-features",{"title":357,"path":358,"stem":359,"icon":68},"Feature contract","\u002Freference\u002Ffeature-contract","4.reference\u002F3.feature-contract",{"title":361,"path":362,"stem":363,"icon":107},"CSS and UI-provider requirements","\u002Freference\u002Fcss-and-ui","4.reference\u002F4.css-and-ui",{"title":365,"path":366,"stem":367,"icon":148},"Vue-free advanced schema","\u002Freference\u002Fadvanced-schema","4.reference\u002F5.advanced-schema",{"title":369,"path":370,"stem":371,"icon":372},"Dependency rules","\u002Freference\u002Fdependency-rules","4.reference\u002F6.dependency-rules","i-lucide-git-branch",{"title":374,"path":375,"stem":376,"icon":377},"Commands","\u002Freference\u002Fcommands","4.reference\u002F7.commands","i-lucide-terminal",{"title":379,"path":380,"stem":381,"icon":163},"Block capability contract","\u002Freference\u002Fblock-capabilities","4.reference\u002F8.block-capabilities",{"title":383,"path":384,"stem":385,"icon":168},"Block type contract","\u002Freference\u002Fblock-types","4.reference\u002F9.block-types",{"title":387,"path":388,"stem":389,"children":390,"icon":393},"AI agents","\u002Fai-agents","5.ai-agents\u002F1.index",[391,394,398,402,407],{"title":392,"path":388,"stem":389,"icon":393},"Overview","i-lucide-bot",{"title":395,"path":396,"stem":397,"icon":198},"Integrate the editor","\u002Fai-agents\u002Fintegrate","5.ai-agents\u002F2.integrate",{"title":399,"path":400,"stem":401,"icon":68},"Add a block or feature","\u002Fai-agents\u002Fextend","5.ai-agents\u002F3.extend",{"title":403,"path":404,"stem":405,"icon":406},"Pitfalls and invariants","\u002Fai-agents\u002Finvariants","5.ai-agents\u002F4.invariants","i-lucide-shield-alert",{"title":408,"path":409,"stem":410,"icon":411},"Verify","\u002Fai-agents\u002Fverify","5.ai-agents\u002F5.verify","i-lucide-check-check",{"id":413,"title":303,"body":414,"description":1542,"extension":1543,"links":1544,"meta":1545,"navigation":1546,"path":304,"seo":1547,"stem":305,"__hash__":1548},"docs\u002F3.guides\u002F51.charts.md",{"type":415,"value":416,"toc":1533},"minimark",[417,451,558,563,752,791,794,969,973,1014,1018,1198,1214,1394,1410,1414,1420,1438,1442,1467,1471,1484,1488,1529],[418,419,420,421,425,426,430,431,433,434,437,438,441,442,446,447,450],"p",{},"The add-on ",[422,423,424],"code",{},"@skaile\u002Fforge-editor-charts"," draws charts from the Blocks of the workspace. A ",[427,428,429],"strong",{},"chart"," is a Typed block of the Block type ",[422,432,429],{},". It stores its ",[427,435,436],{},"configuration"," only (",[422,439,440],{},"meta.chart",", a ",[443,444,445],"a",{"href":176},"Block property"," that has no form field); the numbers are the answer to a ",[443,448,449],{"href":206},"query"," whenever the chart is drawn, so a change of a task changes the chart.",[452,453,454,470],"table",{},[455,456,457],"thead",{},[458,459,460,464,467],"tr",{},[461,462,463],"th",{},"Piece",[461,465,466],{},"What it does",[461,468,469],{},"Where",[471,472,473,489,506,518,539],"tbody",{},[458,474,475,481,486],{},[476,477,478],"td",{},[422,479,480],{},"chartBlockTypes(locale)",[476,482,483,484],{},"the Block type ",[422,485,429],{},[476,487,488],{},"editor and server",[458,490,491,496,503],{},[476,492,493],{},[422,494,495],{},"toQuery(config)",[476,497,498,499,502],{},"the ",[422,500,501],{},"DataQuery"," a chart asks: its own query plus group and aggregates",[476,504,505],{},"anywhere",[458,507,508,513,516],{},[476,509,510],{},[422,511,512],{},"toVegaLite(config, result)",[476,514,515],{},"the pure Vega-Lite specification of the chart",[476,517,505],{},[458,519,520,525,528],{},[476,521,522],{},[422,523,524],{},"chartNodeViews",[476,526,527],{},"the node view that draws the chart and carries the chart editor",[476,529,530,531,534,535,538],{},"editor (",[422,532,533],{},"\u002Fvue",", ",[422,536,537],{},"\u002Freact",")",[458,540,541,546,555],{},[476,542,543],{},[422,544,545],{},"chartTargets({ answer })",[476,547,498,548,551,552],{},[443,549,550],{"href":215},"render target"," ",[422,553,554],{},"chart-svg",[476,556,557],{},"server",[559,560,562],"h2",{"id":561},"the-configuration","The configuration",[564,565,570],"pre",{"className":566,"code":567,"language":568,"meta":569,"style":569},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","interface ChartConfig {\n  type: 'bar' | 'line' | 'pie' | 'scatter'\n  \u002F** Which Blocks the chart is drawn from (Block types, filter). *\u002F\n  query: DataQuery\n  \u002F** The x axis (bar, line, scatter) or the slices (pie): a property key or a pseudo-field such as `$type`. *\u002F\n  x: string\n  \u002F** What is measured: an aggregate of a field, named `as`. *\u002F\n  series: { field?: string, fn: AggregateFn, as: string }[]\n  color?: string\n  stack?: boolean\n}\n","ts","",[422,571,572,589,637,644,655,661,672,678,725,735,746],{"__ignoreMap":569},[573,574,577,581,585],"span",{"class":575,"line":576},"line",1,[573,578,580],{"class":579},"spNyl","interface",[573,582,584],{"class":583},"sBMFI"," ChartConfig",[573,586,588],{"class":587},"sMK4o"," {\n",[573,590,592,596,599,602,606,609,612,614,616,618,620,622,625,627,629,631,634],{"class":575,"line":591},2,[573,593,595],{"class":594},"swJcz","  type",[573,597,598],{"class":587},":",[573,600,601],{"class":587}," '",[573,603,605],{"class":604},"sfazB","bar",[573,607,608],{"class":587},"'",[573,610,611],{"class":587}," |",[573,613,601],{"class":587},[573,615,575],{"class":604},[573,617,608],{"class":587},[573,619,611],{"class":587},[573,621,601],{"class":587},[573,623,624],{"class":604},"pie",[573,626,608],{"class":587},[573,628,611],{"class":587},[573,630,601],{"class":587},[573,632,633],{"class":604},"scatter",[573,635,636],{"class":587},"'\n",[573,638,640],{"class":575,"line":639},3,[573,641,643],{"class":642},"sHwdD","  \u002F** Which Blocks the chart is drawn from (Block types, filter). *\u002F\n",[573,645,647,650,652],{"class":575,"line":646},4,[573,648,649],{"class":594},"  query",[573,651,598],{"class":587},[573,653,654],{"class":583}," DataQuery\n",[573,656,658],{"class":575,"line":657},5,[573,659,660],{"class":642},"  \u002F** The x axis (bar, line, scatter) or the slices (pie): a property key or a pseudo-field such as `$type`. *\u002F\n",[573,662,664,667,669],{"class":575,"line":663},6,[573,665,666],{"class":594},"  x",[573,668,598],{"class":587},[573,670,671],{"class":583}," string\n",[573,673,675],{"class":575,"line":674},7,[573,676,677],{"class":642},"  \u002F** What is measured: an aggregate of a field, named `as`. *\u002F\n",[573,679,681,684,686,689,692,695,698,701,704,706,709,711,714,716,718,721],{"class":575,"line":680},8,[573,682,683],{"class":594},"  series",[573,685,598],{"class":587},[573,687,688],{"class":587}," {",[573,690,691],{"class":594}," field",[573,693,694],{"class":587},"?:",[573,696,697],{"class":583}," string",[573,699,700],{"class":587},",",[573,702,703],{"class":594}," fn",[573,705,598],{"class":587},[573,707,708],{"class":583}," AggregateFn",[573,710,700],{"class":587},[573,712,713],{"class":594}," as",[573,715,598],{"class":587},[573,717,697],{"class":583},[573,719,720],{"class":587}," }",[573,722,724],{"class":723},"sTEyZ","[]\n",[573,726,728,731,733],{"class":575,"line":727},9,[573,729,730],{"class":594},"  color",[573,732,694],{"class":587},[573,734,671],{"class":583},[573,736,738,741,743],{"class":575,"line":737},10,[573,739,740],{"class":594},"  stack",[573,742,694],{"class":587},[573,744,745],{"class":583}," boolean\n",[573,747,749],{"class":575,"line":748},11,[573,750,751],{"class":587},"}\n",[418,753,754,756,757,760,761,764,765,768,769,772,773,534,776,534,779,782,783,786,787,790],{},[422,755,495],{}," copies ",[422,758,759],{},"config.query"," and adds ",[422,762,763],{},"group: { field: config.x, hideEmpty: true }",", one aggregate per series and a row limit, and selects only the fields the chart reads. The Block index answers the grouping (",[422,766,767],{},"backend.index.query","), so a backend that groups in the database sends only the rows the chart needs. A scatter chart has no grouping: it reads the rows. Each group has one point per series: ",[422,770,771],{},"count"," counts the rows, ",[422,774,775],{},"sum",[422,777,778],{},"avg",[422,780,781],{},"min"," and ",[422,784,785],{},"max"," read the numbers of ",[422,788,789],{},"field",". Blocks without a value in the x field are left out of the chart.",[418,792,793],{},"The Block's own chart in the kitchen sink counts tasks per status:",[564,795,799],{"className":796,"code":797,"language":798,"meta":569,"style":569},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{ \"type\": \"bar\", \"query\": { \"v\": 1, \"source\": { \"kind\": \"blocks\", \"blockType\": \"task\" } }, \"x\": \"status\", \"series\": [{ \"fn\": \"count\", \"as\": \"Anzahl\" }] }\n","json",[422,800,801],{"__ignoreMap":569},[573,802,803,806,809,812,815,817,819,821,823,825,827,829,831,833,835,837,840,842,844,848,850,852,855,857,859,861,863,866,868,870,872,875,877,879,881,884,886,888,890,893,895,897,900,902,905,907,909,911,914,916,918,920,923,925,927,930,932,935,937,939,941,943,945,947,949,952,954,956,958,961,963,966],{"class":575,"line":576},[573,804,805],{"class":587},"{",[573,807,808],{"class":587}," \"",[573,810,811],{"class":579},"type",[573,813,814],{"class":587},"\"",[573,816,598],{"class":587},[573,818,808],{"class":587},[573,820,605],{"class":604},[573,822,814],{"class":587},[573,824,700],{"class":587},[573,826,808],{"class":587},[573,828,449],{"class":579},[573,830,814],{"class":587},[573,832,598],{"class":587},[573,834,688],{"class":587},[573,836,808],{"class":587},[573,838,839],{"class":583},"v",[573,841,814],{"class":587},[573,843,598],{"class":587},[573,845,847],{"class":846},"sbssI"," 1",[573,849,700],{"class":587},[573,851,808],{"class":587},[573,853,854],{"class":583},"source",[573,856,814],{"class":587},[573,858,598],{"class":587},[573,860,688],{"class":587},[573,862,808],{"class":587},[573,864,865],{"class":846},"kind",[573,867,814],{"class":587},[573,869,598],{"class":587},[573,871,808],{"class":587},[573,873,874],{"class":604},"blocks",[573,876,814],{"class":587},[573,878,700],{"class":587},[573,880,808],{"class":587},[573,882,883],{"class":846},"blockType",[573,885,814],{"class":587},[573,887,598],{"class":587},[573,889,808],{"class":587},[573,891,892],{"class":604},"task",[573,894,814],{"class":587},[573,896,720],{"class":587},[573,898,899],{"class":587}," },",[573,901,808],{"class":587},[573,903,904],{"class":579},"x",[573,906,814],{"class":587},[573,908,598],{"class":587},[573,910,808],{"class":587},[573,912,913],{"class":604},"status",[573,915,814],{"class":587},[573,917,700],{"class":587},[573,919,808],{"class":587},[573,921,922],{"class":579},"series",[573,924,814],{"class":587},[573,926,598],{"class":587},[573,928,929],{"class":587}," [{",[573,931,808],{"class":587},[573,933,934],{"class":583},"fn",[573,936,814],{"class":587},[573,938,598],{"class":587},[573,940,808],{"class":587},[573,942,771],{"class":604},[573,944,814],{"class":587},[573,946,700],{"class":587},[573,948,808],{"class":587},[573,950,951],{"class":583},"as",[573,953,814],{"class":587},[573,955,598],{"class":587},[573,957,808],{"class":587},[573,959,960],{"class":604},"Anzahl",[573,962,814],{"class":587},[573,964,965],{"class":587}," }]",[573,967,968],{"class":587}," }\n",[559,970,972],{"id":971},"the-vega-lite-specification","The Vega-Lite specification",[418,974,975,977,978,534,980,534,982,985,986,988,989,992,993,995,996,998,999,1001,1002,1005,1006,1009,1010,1013],{},[422,976,512],{}," returns a Vega-Lite 6 specification as a plain object. It is pure: the same configuration and answer give the same specification, and it carries no size. The data are the points in long form (",[422,979,904],{},[422,981,922],{},[422,983,984],{},"value","), so any number of series share one encoding. ",[422,987,605],{}," stacks several series (or puts them side by side with ",[422,990,991],{},"stack: false","), ",[422,994,575],{}," takes a time axis when every x value is a date and a number axis for numbers, ",[422,997,624],{}," shows the first series, ",[422,1000,633],{}," plots two numeric fields. A single series takes ",[422,1003,1004],{},"color","; several take the palette and a legend. Both the node view (",[422,1007,1008],{},"vega-embed",") and the server target (",[422,1011,1012],{},"vega",") draw this one specification.",[559,1015,1017],{"id":1016},"install-and-wire","Install and wire",[564,1019,1021],{"className":566,"code":1020,"language":568,"meta":569,"style":569},"import { defaultBlockTypes } from '@skaile\u002Fforge-editor\u002Fcomposites'\nimport { chartBlockTypes } from '@skaile\u002Fforge-editor-charts\u002Fclient'\nimport { chartNodeViews } from '@skaile\u002Fforge-editor-charts\u002Fvue' \u002F\u002F or '\u002Freact'\n\nconst editor = composeEditor({\n  content: 'rich',\n  blockTypes: [...defaultBlockTypes(t), ...chartBlockTypes('de')],\n  \u002F\u002F The node views by Block type id: a `chart` block draws its chart, every other type keeps its own view.\n  blockNodeViews: chartNodeViews,\n})\n",[422,1022,1023,1046,1066,1089,1095,1116,1133,1174,1179,1190],{"__ignoreMap":569},[573,1024,1025,1029,1031,1034,1036,1039,1041,1044],{"class":575,"line":576},[573,1026,1028],{"class":1027},"s7zQu","import",[573,1030,688],{"class":587},[573,1032,1033],{"class":723}," defaultBlockTypes",[573,1035,720],{"class":587},[573,1037,1038],{"class":1027}," from",[573,1040,601],{"class":587},[573,1042,1043],{"class":604},"@skaile\u002Fforge-editor\u002Fcomposites",[573,1045,636],{"class":587},[573,1047,1048,1050,1052,1055,1057,1059,1061,1064],{"class":575,"line":591},[573,1049,1028],{"class":1027},[573,1051,688],{"class":587},[573,1053,1054],{"class":723}," chartBlockTypes",[573,1056,720],{"class":587},[573,1058,1038],{"class":1027},[573,1060,601],{"class":587},[573,1062,1063],{"class":604},"@skaile\u002Fforge-editor-charts\u002Fclient",[573,1065,636],{"class":587},[573,1067,1068,1070,1072,1075,1077,1079,1081,1084,1086],{"class":575,"line":639},[573,1069,1028],{"class":1027},[573,1071,688],{"class":587},[573,1073,1074],{"class":723}," chartNodeViews",[573,1076,720],{"class":587},[573,1078,1038],{"class":1027},[573,1080,601],{"class":587},[573,1082,1083],{"class":604},"@skaile\u002Fforge-editor-charts\u002Fvue",[573,1085,608],{"class":587},[573,1087,1088],{"class":642}," \u002F\u002F or '\u002Freact'\n",[573,1090,1091],{"class":575,"line":646},[573,1092,1094],{"emptyLinePlaceholder":1093},true,"\n",[573,1096,1097,1100,1103,1106,1110,1113],{"class":575,"line":657},[573,1098,1099],{"class":579},"const",[573,1101,1102],{"class":723}," editor ",[573,1104,1105],{"class":587},"=",[573,1107,1109],{"class":1108},"s2Zo4"," composeEditor",[573,1111,1112],{"class":723},"(",[573,1114,1115],{"class":587},"{\n",[573,1117,1118,1121,1123,1125,1128,1130],{"class":575,"line":663},[573,1119,1120],{"class":594},"  content",[573,1122,598],{"class":587},[573,1124,601],{"class":587},[573,1126,1127],{"class":604},"rich",[573,1129,608],{"class":587},[573,1131,1132],{"class":587},",\n",[573,1134,1135,1138,1140,1143,1146,1149,1152,1154,1157,1160,1162,1164,1167,1169,1172],{"class":575,"line":674},[573,1136,1137],{"class":594},"  blockTypes",[573,1139,598],{"class":587},[573,1141,1142],{"class":723}," [",[573,1144,1145],{"class":587},"...",[573,1147,1148],{"class":1108},"defaultBlockTypes",[573,1150,1151],{"class":723},"(t)",[573,1153,700],{"class":587},[573,1155,1156],{"class":587}," ...",[573,1158,1159],{"class":1108},"chartBlockTypes",[573,1161,1112],{"class":723},[573,1163,608],{"class":587},[573,1165,1166],{"class":604},"de",[573,1168,608],{"class":587},[573,1170,1171],{"class":723},")]",[573,1173,1132],{"class":587},[573,1175,1176],{"class":575,"line":680},[573,1177,1178],{"class":642},"  \u002F\u002F The node views by Block type id: a `chart` block draws its chart, every other type keeps its own view.\n",[573,1180,1181,1184,1186,1188],{"class":575,"line":727},[573,1182,1183],{"class":594},"  blockNodeViews",[573,1185,598],{"class":587},[573,1187,1074],{"class":723},[573,1189,1132],{"class":587},[573,1191,1192,1195],{"class":575,"line":737},[573,1193,1194],{"class":587},"}",[573,1196,1197],{"class":723},")\n",[418,1199,1200,1203,1204,534,1207,534,1210,1213],{},[422,1201,1202],{},"blockNodeViews"," is an option of the composites feature (",[422,1205,1206],{},"composeEditor",[422,1208,1209],{},"AdvancedEditor",[422,1211,1212],{},"ComposedSurface","): a node view per Block type id that replaces the standard Typed block view for that type. The title, the chrome and the content of the block stay; the view adds the chart.",[564,1215,1217],{"className":566,"code":1216,"language":568,"meta":569,"style":569},"import { createRenderer, markdownTarget } from '@skaile\u002Fforge-editor\u002Fadapters\u002Frender'\nimport { answerFromDocument, chartBlockTypes, chartTargets } from '@skaile\u002Fforge-editor-charts\u002Fserver'\n\n\u002F\u002F installEditorServer({ ports: { render }, blockTypes })\nconst answer = answerFromDocument({ load: async id => (await getDocument(id))?.content ?? null, blockTypes: [...serverBlockTypes] })\nexport const render = createRenderer([markdownTarget(), ...chartTargets({ answer })])\n",[422,1218,1219,1244,1273,1277,1282,1352],{"__ignoreMap":569},[573,1220,1221,1223,1225,1228,1230,1233,1235,1237,1239,1242],{"class":575,"line":576},[573,1222,1028],{"class":1027},[573,1224,688],{"class":587},[573,1226,1227],{"class":723}," createRenderer",[573,1229,700],{"class":587},[573,1231,1232],{"class":723}," markdownTarget",[573,1234,720],{"class":587},[573,1236,1038],{"class":1027},[573,1238,601],{"class":587},[573,1240,1241],{"class":604},"@skaile\u002Fforge-editor\u002Fadapters\u002Frender",[573,1243,636],{"class":587},[573,1245,1246,1248,1250,1253,1255,1257,1259,1262,1264,1266,1268,1271],{"class":575,"line":591},[573,1247,1028],{"class":1027},[573,1249,688],{"class":587},[573,1251,1252],{"class":723}," answerFromDocument",[573,1254,700],{"class":587},[573,1256,1054],{"class":723},[573,1258,700],{"class":587},[573,1260,1261],{"class":723}," chartTargets",[573,1263,720],{"class":587},[573,1265,1038],{"class":1027},[573,1267,601],{"class":587},[573,1269,1270],{"class":604},"@skaile\u002Fforge-editor-charts\u002Fserver",[573,1272,636],{"class":587},[573,1274,1275],{"class":575,"line":639},[573,1276,1094],{"emptyLinePlaceholder":1093},[573,1278,1279],{"class":575,"line":646},[573,1280,1281],{"class":642},"\u002F\u002F installEditorServer({ ports: { render }, blockTypes })\n",[573,1283,1284,1286,1289,1291,1293,1295,1297,1300,1302,1305,1309,1312,1315,1318,1321,1324,1327,1330,1333,1336,1339,1341,1343,1345,1348,1350],{"class":575,"line":657},[573,1285,1099],{"class":579},[573,1287,1288],{"class":723}," answer ",[573,1290,1105],{"class":587},[573,1292,1252],{"class":1108},[573,1294,1112],{"class":723},[573,1296,805],{"class":587},[573,1298,1299],{"class":1108}," load",[573,1301,598],{"class":587},[573,1303,1304],{"class":579}," async",[573,1306,1308],{"class":1307},"sHdIc"," id",[573,1310,1311],{"class":579}," =>",[573,1313,1314],{"class":723}," (",[573,1316,1317],{"class":1027},"await",[573,1319,1320],{"class":1108}," getDocument",[573,1322,1323],{"class":723},"(id))",[573,1325,1326],{"class":587},"?.",[573,1328,1329],{"class":723},"content ",[573,1331,1332],{"class":587},"??",[573,1334,1335],{"class":587}," null,",[573,1337,1338],{"class":594}," blockTypes",[573,1340,598],{"class":587},[573,1342,1142],{"class":723},[573,1344,1145],{"class":587},[573,1346,1347],{"class":723},"serverBlockTypes] ",[573,1349,1194],{"class":587},[573,1351,1197],{"class":723},[573,1353,1354,1357,1360,1363,1365,1367,1370,1373,1376,1378,1380,1383,1385,1387,1389,1391],{"class":575,"line":663},[573,1355,1356],{"class":1027},"export",[573,1358,1359],{"class":579}," const",[573,1361,1362],{"class":723}," render ",[573,1364,1105],{"class":587},[573,1366,1227],{"class":1108},[573,1368,1369],{"class":723},"([",[573,1371,1372],{"class":1108},"markdownTarget",[573,1374,1375],{"class":723},"()",[573,1377,700],{"class":587},[573,1379,1156],{"class":587},[573,1381,1382],{"class":1108},"chartTargets",[573,1384,1112],{"class":723},[573,1386,805],{"class":587},[573,1388,1288],{"class":723},[573,1390,1194],{"class":587},[573,1392,1393],{"class":723},")])\n",[418,1395,1396,1397,1399,1400,1402,1403,1405,1406,1409],{},"The entry ",[422,1398,1063],{}," reaches neither ",[422,1401,1012],{}," nor the render target; ",[422,1404,1008],{}," loads when the first chart draws. The ",[422,1407,1408],{},"\u002Fserver"," entry reaches no editor code and needs no DOM.",[559,1411,1413],{"id":1412},"in-the-editor","In the editor",[418,1415,1416,1417,1419],{},"The node view asks ",[422,1418,767],{}," (the Blocks of every Document the user may read) and, for a backend without it, answers the same query over the Blocks of the open Document. It asks again while the chart is visible: after a change of the block or of the Blocks (debounced), and every few seconds, because Blocks of other Documents change without the editor hearing of it. A query the Block index refuses shows its message instead of a chart.",[418,1421,1422,1423,1426,1427,1430,1431,1433,1434,1437],{},"An editable chart has a ",[427,1424,1425],{},"Diagramm einstellen"," button that opens the chart editor under the chart: the chart type, the x field, the series (aggregate, field, name), the colour, stacking, and the library's ",[443,1428,1429],{"href":206},"query builder"," for the Blocks the chart is drawn from. Every change writes ",[422,1432,440],{}," through ",[422,1435,1436],{},"setBlockProperty",", one key, so collaborators' other properties survive.",[559,1439,1441],{"id":1440},"render-target","Render target",[418,1443,1444,1446,1447,1449,1450,1452,1453,1314,1456,1459,1460,1463,1464,1466],{},[422,1445,545],{}," gives ",[422,1448,554],{}," for a Block of the type ",[422,1451,429],{},": the query is answered by ",[422,1454,1455],{},"answer",[422,1457,1458],{},"answerFromDocument"," reads the Blocks of the Document the render is for), the specification is compiled with ",[422,1461,1462],{},"vega-lite",", and ",[422,1465,1012],{}," renders the SVG without a DOM or a canvas. The file is named after the chart's title. A render of any other block fails with a message the client shows.",[559,1468,1470],{"id":1469},"strings","Strings",[418,1472,1473,1474,534,1477,1480,1481,1483],{},"The add-on keeps its own small catalog in German and English (",[422,1475,1476],{},"CHARTS_MESSAGES",[422,1478,1479],{},"createChartsTranslator(locale, overrides)","), because the library's message keys are closed over the library's own strings. ",[422,1482,480],{}," takes the language; the node view reads it from the editor context.",[559,1485,1487],{"id":1486},"in-the-demo-app","In the demo app",[418,1489,1490,1491,1494,1495,1314,1498,1500,1501,1314,1503,1505,1506,1509,1510,1513,1514,1517,1518,1520,1521,1524,1525,1528],{},"The charts always draw on ",[422,1492,1493],{},"\u002Fkitchen-sink\u002Fdatabases",": the page imports the add-on's ",[422,1496,1497],{},"\u002Fclient",[422,1499,1159],{},") and ",[422,1502,533],{},[422,1504,524],{},") entries itself, whatever ",[422,1507,1508],{},"NUXT_PUBLIC_ADDONS_CHARTS"," says, and gives its editor a backend without a Block index, so the charts and the data views beside them answer from the open document. Its „Task tracker“ sample has eight tasks, two data views and two charts over them. ",[422,1511,1512],{},"NUXT_PUBLIC_ADDONS_CHARTS=1"," (see ",[422,1515,1516],{},".env.example","; a runtime flag, read by the server and the browser alike) adds the server's target ",[422,1519,554],{},", the SVG export; without it the page shows a hint card. The documents under ",[422,1522,1523],{},"\u002Fdocuments"," load the Block type and the node view only with the flag on. See ",[443,1526,131],{"href":1527},"\u002Fguides\u002Fadvanced-nuxt-example#databases",".",[1530,1531,1532],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":569,"searchDepth":591,"depth":591,"links":1534},[1535,1536,1537,1538,1539,1540,1541],{"id":561,"depth":591,"text":562},{"id":971,"depth":591,"text":972},{"id":1016,"depth":591,"text":1017},{"id":1412,"depth":591,"text":1413},{"id":1440,"depth":591,"text":1441},{"id":1469,"depth":591,"text":1470},{"id":1486,"depth":591,"text":1487},"The add-on @skaile\u002Fforge-editor-charts: the Block type chart, its configuration and the query it derives, the pure Vega-Lite specification, the node view with a chart editor for Vue and React, and the render target chart-svg.","md",null,{},{"icon":306},{"title":303,"description":1542},"cBwf6G9yTldRR8dUGbCq2WvFRFH9-X34Oi5L00rY0qQ",[1550,1552],{"title":296,"path":297,"stem":298,"description":1551,"icon":301,"children":-1},"The @skaile\u002Fforge-editor-index-pg add-on: trigram title search, a vector table kept current on replace, nearest and related Blocks, query pushdown, and the Embedder port with its OpenAI-compatible adapter.",{"title":308,"path":309,"stem":310,"description":1553,"icon":73,"children":-1},"Collaboration is a feature: mount a surface with a Yjs session, per-client undo, authors and comments, positions that survive concurrent edits, and matching schemas.",1793213908541]