Text¶
This example places semantic text items in data coordinates.
Preview¶
Run And Adapt¶
Commands below assume a Datoviz source checkout and start at the repository root. Use your configured build environment; Python routes additionally require local bindings.
| Route | Availability | Command or action |
|---|---|---|
| C | Canonical native source | just example-c visuals/text (build and run), or rerun ./build/examples/c/visuals/text |
| Python | Available; manually maintained direct-engine example | python3 -m examples.python.gallery.visuals.text |
| Browser | Live WebGPU route | Open live example |
This example is approved as a starting point for user code and coding agents. Keep the object lifetimes and data shapes intact while adapting the data and styling.
What To Look For¶
Each text item provides a string, x/y data position, font size, angle, and color role, then the text system lowers it to atlas glyphs. Compare the headline, smaller annotations, and rotated label to see how titles, units, and short scientific notes can be added without managing glyph quads manually.
Source¶
#!/usr/bin/env python3
"""Retained semantic text items in panel data coordinates."""
from __future__ import annotations
import ctypes
import datoviz as dvz
from examples.python.gallery import common as ex
def main() -> None:
scene, figure, panel = ex.scene_panel()
text = dvz.dvz_text(panel, 0)
if not text:
raise RuntimeError("dvz_text() failed")
style = dvz.dvz_text_style()
style.renderer = dvz.DVZ_TEXT_RENDERER_MSDF_ATLAS
if dvz.dvz_text_set_style(text, ctypes.byref(style)) != 0:
raise RuntimeError("dvz_text_set_style() failed")
placement = dvz.dvz_text_placement()
placement.mode = dvz.DVZ_TEXT_PLACEMENT_DATA
if dvz.dvz_text_set_placement(text, ctypes.byref(placement)) != 0:
raise RuntimeError("dvz_text_set_placement() failed")
strings = [
b"Retained text",
b"semantic strings, data anchored",
b"MSDF atlas renderer",
b"panzoom follows data coordinates",
b"rotated label",
]
positions = [
(-0.80, +0.50, 0.0),
(-0.79, +0.16, 0.0),
(-0.78, -0.12, 0.0),
(-0.77, -0.38, 0.0),
(+0.32, -0.58, 0.0),
]
sizes = [60.0, 34.0, 28.0, 22.0, 26.0]
angles = [0.0, 0.0, 0.0, 0.0, -0.34]
colors = [ex.TEXT, ex.CYAN, ex.GREEN, ex.BLUE, ex.YELLOW]
items = (dvz.DvzTextItem * len(strings))()
for item, string, position, size, angle, color in zip(
items, strings, positions, sizes, angles, colors, strict=True
):
item.string = string
item.position[:] = position
item.anchor[:] = (0.0, 0.5)
item.size_px = size
item.color = color
item.angle = angle
if dvz.dvz_text_set_items(text, items, len(items)) != 0:
raise RuntimeError("dvz_text_set_items() failed")
ex.run_with_view(
scene,
figure,
"Text",
lambda view: ex.bind_panzoom(view, scene, panel, dvz.DVZ_DIM_MASK_XY),
)
if __name__ == "__main__":
main()
/*
* Copyright (c) 2021 Cyrille Rossant and contributors. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project root for details.
* SPDX-License-Identifier: MIT
*/
/* text - This example places retained semantic text items in data coordinates.
*
* What to look for: each text item provides a string, x/y data position, font size, angle, and
* color role, then the text system lowers it to atlas glyphs. Compare the headline, smaller
* annotations, and rotated label to see how titles, units, and short scientific notes can be added
* without managing glyph quads manually.
*
* Scenario: visuals_text
* Style: visuals, graphite_cyan, 1280x720 window target
*
* Build: just example-c visuals/text
* Run: ./build/examples/c/visuals/text --live
* Smoke: ./build/examples/c/visuals/text --png
*/
/*************************************************************************************************/
/* Includes */
/*************************************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include "_alloc.h"
#include "_assertions.h"
#include "datoviz/scene.h"
#include "example_style.h"
#include "runner/scenario_runner.h"
/*************************************************************************************************/
/* Constants */
/*************************************************************************************************/
#define WIDTH EXAMPLE_WINDOW_WIDTH
#define HEIGHT EXAMPLE_WINDOW_HEIGHT
#define TEXT_COUNT 5u
/*************************************************************************************************/
/* Forward declarations */
/*************************************************************************************************/
DvzScenarioSpec dvz_visual_text_scenario(void);
/*************************************************************************************************/
/* Structs */
/*************************************************************************************************/
typedef struct TextVisualState
{
DvzText* text;
uint32_t logical_width;
uint32_t logical_height;
} TextVisualState;
/*************************************************************************************************/
/* Helpers */
/*************************************************************************************************/
/**
* Update retained text items for the current logical panel size.
*
* @param state text visual state
* @param logical_width current logical panel width
* @param logical_height current logical panel height
* @return true when the text items were updated
*/
static bool _set_text_items(
TextVisualState* state, uint32_t logical_width, uint32_t logical_height)
{
ANN(state);
ANN(state->text);
if (logical_width == 0 || logical_height == 0)
return false;
if (state->logical_width == logical_width && state->logical_height == logical_height)
return true;
const char* strings[TEXT_COUNT] = {
"Retained text", "semantic strings, data anchored",
"MSDF atlas renderer", "panzoom follows data coordinates",
"rotated label",
};
const float x[TEXT_COUNT] = {-0.80f, -0.79f, -0.78f, -0.77f, +0.32f};
const float y[TEXT_COUNT] = {+0.50f, +0.16f, -0.12f, -0.38f, -0.58f};
const float sizes[TEXT_COUNT] = {60.0f, 34.0f, 28.0f, 22.0f, 26.0f};
const float angles[TEXT_COUNT] = {0.0f, 0.0f, 0.0f, 0.0f, -0.34f};
const ExampleStyleColorRole roles[TEXT_COUNT] = {
EXAMPLE_STYLE_COLOR_TEXT,
EXAMPLE_STYLE_COLOR_ACCENT_PRIMARY,
EXAMPLE_STYLE_COLOR_ACCENT_SECONDARY,
EXAMPLE_STYLE_COLOR_MINOR_TICK,
EXAMPLE_STYLE_COLOR_WARNING,
};
DvzTextItem items[TEXT_COUNT] = {0};
for (uint32_t i = 0; i < TEXT_COUNT; i++)
{
DvzColor color = example_graphite_cyan_color(roles[i]);
items[i] = (DvzTextItem){DVZ_STRUCT_INIT_FIELDS(DvzTextItem),
.string = strings[i],
.position = {x[i], y[i], 0.0},
.anchor = {0.0f, 0.5f},
.size_px = sizes[i],
.color = color,
.angle = angles[i]};
}
if (dvz_text_set_items(state->text, items, TEXT_COUNT) != 0)
return false;
state->logical_width = logical_width;
state->logical_height = logical_height;
return true;
}
/**
* Add the retained text examples to one panel.
*
* @param panel target panel
* @param logical_width current logical panel width
* @param logical_height current logical panel height
* @param out_state output text visual state
* @return true when all text objects were added
*/
static bool _add_texts(
DvzPanel* panel, uint32_t logical_width, uint32_t logical_height, TextVisualState** out_state)
{
ANN(panel);
ANN(out_state);
*out_state = NULL;
TextVisualState* state = (TextVisualState*)dvz_calloc(1, sizeof(*state));
if (state == NULL)
return false;
DvzText* text = dvz_text(panel, 0);
if (text == NULL)
goto error;
state->text = text;
DvzTextStyle style = dvz_text_style();
style.renderer = DVZ_TEXT_RENDERER_MSDF_ATLAS;
if (dvz_text_set_style(text, &style) != 0)
goto error;
DvzTextPlacement placement = dvz_text_placement();
placement.mode = DVZ_TEXT_PLACEMENT_DATA;
if (dvz_text_set_placement(text, &placement) != 0)
goto error;
if (!_set_text_items(state, logical_width, logical_height))
goto error;
*out_state = state;
return true;
error:
dvz_free(state);
return false;
}
/*************************************************************************************************/
/* Scenario callbacks */
/*************************************************************************************************/
/**
* Initialize the retained semantic text scenario.
*
* @param ctx scenario context
* @param out_user scenario state output
* @return true on success
*/
static bool _scenario_init(DvzScenarioContext* ctx, void** out_user)
{
if (ctx == NULL)
return false;
if (out_user != NULL)
*out_user = NULL;
ctx->figure = dvz_figure(ctx->scene, ctx->width, ctx->height, 0);
if (ctx->figure == NULL)
return false;
DvzPanel* panel = dvz_panel_full(ctx->figure);
if (panel == NULL)
return false;
example_graphite_cyan_set_panel_background(panel);
TextVisualState* state = NULL;
if (!_add_texts(panel, ctx->width, ctx->height, &state))
return false;
if (dvz_scenario_panzoom(ctx, panel, NULL, DVZ_DIM_MASK_XY) == NULL)
{
dvz_free(state);
return false;
}
if (out_user != NULL)
*out_user = state;
return true;
}
/**
* Handle portable scenario events.
*
* @param ctx scenario context
* @param event portable event
* @param user scenario state
*/
static void _scenario_event(DvzScenarioContext* ctx, const DvzScenarioEvent* event, void* user)
{
TextVisualState* state = (TextVisualState*)user;
if (ctx == NULL || event == NULL || state == NULL)
return;
if (event->kind != DVZ_SCENARIO_EVENT_RESIZE)
return;
(void)_set_text_items(state, ctx->width, ctx->height);
}
/**
* Free the text visual state.
*
* @param ctx scenario context
* @param user scenario state
*/
static void _scenario_destroy(DvzScenarioContext* ctx, void* user)
{
(void)ctx;
dvz_free(user);
}
/**
* Return the semantic text scenario specification.
*
* @return scenario specification
*/
DvzScenarioSpec dvz_visual_text_scenario(void)
{
return (DvzScenarioSpec){
.id = "visuals_text",
.title = "Text",
.width = WIDTH,
.height = HEIGHT,
.fps = 60.0,
.init = _scenario_init,
.event = _scenario_event,
.destroy = _scenario_destroy,
};
}
/*************************************************************************************************/
/* Functions */
/*************************************************************************************************/
/**
* Run the retained semantic text example through the native scenario runner.
*
* @param argc command-line argument count
* @param argv command-line argument vector
* @return process exit code
*/
#ifndef DVZ_EXAMPLE_NO_MAIN
int main(int argc, char** argv)
{
DvzScenarioSpec spec = dvz_visual_text_scenario();
return dvz_scenario_run_native_cli(&spec, argc, argv) == 0 ? 0 : 1;
}
#endif
Example details
- ID:
visuals_text - Category:
visual - Lane:
visuals - Status:
supported - Source:
examples/c/visuals/text.c - Approved adaptation starter:
yes - Reference: Text visual family
- Python source:
examples/python/gallery/visuals/text.py - Python adaptation: Available; manually maintained direct-engine example
- Browser support: Live in browser
- WebGPU live route:
examples/webgpu/live.html?id=visuals_text - Browser capability tags:
text,glyph-atlas,panzoom - Validation:
smoke+screenshot
Tags
text, panzoom, capture
Data
| Field | Value |
|---|---|
kind |
synthetic |
