FastReport Online Designer lets you add your own report components — with their own icon in the palette, properties in the Properties panel and their own settings dialog. No magic involved: you write a JavaScript plugin, upload it to the builder, and it gets compiled right into the designer build.
In this article we will create a component called «Rating» from scratch, which displays a value as stars, and go the whole way: from downloading the SDK to a ready-made designer build with the plugin and the server-side part.
Â
Â
The component has two halves:
.frx.What ties them together is the type name: the short name of the .NET class, the type field in the plugin and the XML tag in .frx must all be one and the same string.
The two halves can be done one after another. The designer does not need the .NET class, so first we will build and test the plugin, and add the server-side part at the end.
Â
Â
In the builder, open Build → Custom components and click Download SDK. The archive contains README.md with a brief introduction and examples/DemoChartObject — a working example.
The plugin folder also serves as a working folder for your IDE. Copy examples/DemoChartObject and rename the copy to RatingObject: it already has everything ready for autocompletion — sdk.d.ts with SDK types, jsconfig.json and package.json with React types matching the React version of the designer. Run npm install in this folder and open it in your IDE.
Â
A plugin — a folder with the file index.jsx (or index.js). Replace the contents of RatingObject/index.jsx with the component description:
import React from 'react';
import {registerComponent, tr} from 'sdk';
import {Input, ColorInput, Button, FormField} from 'sdk/controls';
registerComponent({
apiVersion: 1,
type: 'RatingObject',
core: 'net',
palette: {
title: 'Rating',
info: 'Star rating',
icon: 'icon-chart',
},
defaultValues: {
'Value': 3,
'Maximum': 5,
'StarColor': '#f5a623',
},
size: {width: 160, height: 32},
properties: [
{prop: 'Data:Value', type: 'number', label: 'Value', attrs: {min: 0}},
{prop: 'Data:Maximum', type: 'number', label: 'Maximum', attrs: {min: 1}},
{prop: 'Appearance:StarColor', type: 'color', label: 'Star color'},
],
});
This is already enough for the component to appear in the palette and get its properties:
palette sets the card in the palette. The icon here is the standard one, but you can also specify your own SVG or PNG as a data:-URI.defaultValues stores the default values. Only values that differ from them end up in .frx — FastReport .NET works the same way.FastReport .NET.properties describes the fields of the properties panel in the format Category:Name. Fields Design:Name and Layout:Left/Top/Width/Height are added by the SDK itself.There is no need to save and read .frx manually: the inherited implementation already knows how to work with all declared properties.
Â
To make the component look like a rating on the page, add the draw method to the description. The frame, moving and resizing are provided to the component by the base class Component, so draw is only responsible for the content. Drawing must be done into the this.$content container: by the time it is called, it has already been created.
draw: function () {
if (!this.$stars) {
this.$stars = document.createElementNS('http://www.w3.org/2000/svg', 'g');
this.$content.append(this.$stars);
}
const maximum = Number(this.prop('Maximum')) || 1;
const value = Number(this.prop('Value')) || 0;
const color = String(this.prop('StarColor'));
const height = this.prop('Height');
const step = this.prop('Width') / maximum;
const stars = [];
for (let i = 0; i < maximum; i++) {
const fill = i < value ? color : '#d9d9d9';
stars.push(`<text x="${step * (i + 0.5)}" y="${height * 0.75}" text-anchor="middle" font-size="${height * 0.8}" fill="${fill}">★</text>`);
}
this.$stars.innerHTML = stars.join('');
},
Â
The settings dialog opens with a double click on the component. We will assemble it from the standard controls of sdk/controls, so that it looks like the built-in editors:
function RatingDialog ({component, popup}) {
const ok = () => {
component.model.submit();
popup.submitAndClose();
component.render();
};
const cancel = () => {
component.model.clear();
popup.close();
};
return (
<div>
<FormField label={`${tr('Value')}:`}>
<Input half type="number" min={0} model={component.model} prop="Value"/>
</FormField>
<FormField label={`${tr('Maximum')}:`}>
<Input half type="number" min={1} model={component.model} prop="Maximum"/>
</FormField>
<FormField label={`${tr('Star color')}:`}>
<ColorInput half model={component.model} prop="StarColor"/>
</FormField>
<div style={{textAlign: 'right'}}>
<Button variant="primary" text="OK" minWidth={60} style={{marginRight: 6}} onClick={ok}/>
<Button minWidth={60} text={tr('Cancel')} onClick={cancel}/>
</div>
</div>
);
}
The controls write changes to component.model. It is a draft: the actual properties of the component are changed only after submit(), so the Cancel button does not break anything.
Connect the dialog in the component description:
editor: (component, popup) => <RatingDialog component={component} popup={popup}/>,
Â
The plugin must contain its own translations. It is convenient to use the English text as the key: if there is no translation, the designer will show the key itself.
const TRANSLATIONS = {
en: {'Rating': 'Rating', 'Star rating': 'Star rating', 'Value': 'Value', 'Maximum': 'Maximum', 'Star color': 'Star color', 'Cancel': 'Cancel'},
de: {'Rating': 'Bewertung', 'Star rating': 'Bewertung in Sternen', 'Value': 'Wert', 'Maximum': 'Maximum', 'Star color': 'Sternfarbe', 'Cancel': 'Abbrechen'},
};
Add the string translations: TRANSLATIONS to the component description. The designer will translate the captions in the palette and the properties panel by itself, and in your own code use tr('Value').
Â
RatingObject. There is no need to delete node_modules before packing — the builder will take into account only the packages from dependencies, while devDependencies (including the React types) will not get into the build.Open the designer: Rating has appeared in the palette. Add it to the page, change the value in the properties panel and open the settings dialog with a double click.
If you build the designer via the Builder API, upload the archive with a POST /builderAPI/extensions request and list the plugins in the build request: "extensions": ["RatingObject"].
Â
For the server to be able to build a report with the new object, a .NET class with the same name in a separate assembly is required:
public class RatingObject : ReportComponentBase
{
// Draw, Serialize, Deserialize, Assign
}
public class RatingAssemblyInitializer : AssemblyInitializerBase
{
public RatingAssemblyInitializer()
{
RegisteredObjects.Add(typeof(RatingObject), "ReportPage", myBitmap, "Rating");
}
}
The assembly is connected through the <Plugins> section in FastReport.config or by a direct call at application startup. A ready-made example of such a plugin — Extras/Misc/TeeChartObjectPlugin in FastReport .NET.
While the class is not deployed, the server will not be able to read the report with this object and will throw ClassException — including when building the preview. The designer build without the plugin will nevertheless open the report and save the unknown object with its tag, attributes and nested XML elements.
Â
Â
The plugin can do more than shown in the article: inherit the behavior of the standard components via extends, connect custom property editors via registerPropertyEditor and use third-party libraries — they are installed via npm install <package> and packed together with node_modules. All this is described in the «Custom components» chapter of the Online Designer user manual, and the DemoChartObject example shows these techniques in working code.
Â
Â
Yes, the JS plugin is enough for working in the designer. But without a class on the server, a report with this component cannot be built: the server will throw ClassException.
Specify in palette.icon your own SVG or PNG as a data:-URI. Without it, the SDK will substitute the standard icon.
There must be a single plugin folder at the root of the archive, and in it — the file index.jsx or index.js. The builder will show the list of problems right away at upload.
Â
Â
A custom component for FastReport Online Designer — two halves tied together by the same type name: a JS plugin for the editor and a .NET class for the server. To assemble everything today, download the SDK, copy the DemoChartObject example and substitute your own properties, preview and settings dialog — the designer will be rebuilt together with the plugin. Connect the server-side part in parallel: even before the class is deployed, a report with the new component can be opened and saved without losses.