UNPKG

devexpress-reporting

Version:

DevExpress Reporting provides the capability to develop a reporting application to create and customize reports.

261 lines (260 loc) 14.2 kB
/** * DevExpress HTML/JS Reporting (designer\controls\xrCharactercomb.js) * Version: 25.1.3 * Build date: Jun 26, 2025 * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * License: https://www.devexpress.com/Support/EULAs/universal.xml */ import { extend, pixelToUnits, roundingXDecimals, unitsToPixel } from '@devexpress/analytics-core/analytics-internal'; import { FontModel } from '@devexpress/analytics-core/analytics-widgets-internal'; import * as ko from 'knockout'; import { TextElementSizeHelper } from '../helpers/_textElementSizeHelper'; import { CharacterCombHelper } from './utils/_charactercombHelper'; import { XRControlSurface, XRControlViewModel } from './xrControl'; import { XRReportElementViewModel } from './xrReportelement'; export class XRCharacterComb extends XRControlViewModel { isPropertyDisabled(name) { if (name === 'cellWidth') { return this.sizeMode() === 'AutoSize' || this.sizeMode() === 'AutoWidth'; } if (name === 'cellHeight') { return this.sizeMode() === 'AutoSize' || this.sizeMode() === 'AutoHeight'; } return super.isPropertyDisabled(name); } _createCellSideFromOriginalSide(originalCellSide, isHeight) { return ko.pureComputed({ read: () => { switch (this.sizeMode()) { case 'AutoSize': return null; case 'AutoWidth': return isHeight ? originalCellSide() : null; case 'AutoHeight': return !isHeight ? originalCellSide() : null; case 'Custom': return originalCellSide(); } }, write: (val) => { originalCellSide(val); } }); } constructor(control, parent, serializer) { super(control, parent, serializer); const _originalCellWidth = this.cellWidth; const _originalCellHeight = this.cellHeight; this._disposables.push(this.cellWidth = this._createCellSideFromOriginalSide(_originalCellWidth, false)); this._disposables.push(this.cellHeight = this._createCellSideFromOriginalSide(_originalCellHeight, true)); const fontModel = new FontModel(this.font); const borderWidth = ko.computed(() => { if (this['borders']() && this['borders']() !== 'None') { return this['borderWidth'](); } else { return 0; } }); this._disposables.push(borderWidth); const textSizeHelper = new TextElementSizeHelper(); this.autoCellSide = ko.observable(this.cellHeight()); this._disposables.push(ko.computed(() => { if (this.sizeMode() !== 'Custom') { const characterHeight = textSizeHelper.getTextContainerSize('a', { 'font-size': fontModel.size() + fontModel.unit(), 'font-family': fontModel.family(), 'height': 'auto', 'width': 'auto' }, 0).height; let side = characterHeight * 1.5 + 2 * borderWidth(); if (this.parentModel()) { side = pixelToUnits(side, this.parentModel().root['measureUnit'](), 1); } this.autoCellSide(side); } })); } roundSize() { this.size.width(Math.ceil(this.size.width())); this.size.height(Math.ceil(this.size.height())); } } XRCharacterComb.unitProperties = [].concat(['cellWidth', 'cellHeight', 'verticalSpacing', 'horizontalSpacing'], XRReportElementViewModel.unitProperties); export class XRCharacterCombSurface extends XRControlSurface { _createCell(text, position) { return { text: ko.observable(text), left: ko.computed(() => { const _horizontalSpacing = this.horizontalSpacing(); const borderWidth = this._getBorderWidthBySpacing(_horizontalSpacing); const line = Math.floor((position) / this.horizontal()); let column = position - (this.horizontal() * line); if (this.rtl()) { column = (this.horizontal() * (line + 1)) - (position + 1); } return column * (this.cellSize.width() + _horizontalSpacing - borderWidth) + this.leftEmptySpace(); }), top: ko.computed(() => { const _verticalSpacing = this.verticalSpacing(); const borderWidth = this._getBorderWidthBySpacing(_verticalSpacing); const line = Math.floor((position) / this.horizontal()); return line * (this.cellSize.height() + _verticalSpacing - borderWidth) + this.topEmptySpace(); }), size: this.cellSize, isEmpty: false }; } _updateCellsText(textAlignment) { const alignments = CharacterCombHelper.getAlignments(textAlignment); const texts = CharacterCombHelper.getLines(this.displayText(), this.horizontal.peek(), this._control.multiline(), this._control['wordWrap'] && this._control['wordWrap']()); CharacterCombHelper.setText(texts, this.cells.peek(), (texts, position) => { return CharacterCombHelper.getTextOffset(texts, position, alignments.vertical, alignments.horizontal, this.vertical.peek(), this.horizontal.peek()); }); } _getBorderWidthBySpacing(spacing) { return (!spacing && this.borders() && this.borders() !== 'None') ? this.borderWidth() : 0; } _applyBounds(newRect, newHorizontal, newVertical, multiline, wordwrap) { if (newVertical <= this.vertical()) { const notEmptyCells = this.cells().filter(cell => !cell.isEmpty); const cellLefts = notEmptyCells.map(cell => cell.left()); newRect.top += notEmptyCells[0].top(); if (newHorizontal <= this.horizontal()) newRect.left += Math.min(...cellLefts); } else if (newHorizontal <= this.horizontal()) { const newCells = []; this.updateArray(newVertical * newHorizontal, newCells); const alignments = CharacterCombHelper.getAlignments(this.getControlModel()['textAlignment']()); const texts = CharacterCombHelper.getLines(this.displayText(), newHorizontal, multiline, wordwrap); CharacterCombHelper.setText(texts, newCells, (texts, position) => { return CharacterCombHelper.getTextOffset(texts, position, alignments.vertical, alignments.horizontal, newVertical, newHorizontal); }); const newCellsLefts = newCells.filter(cell => !cell.isEmpty).map(cell => cell.left()); newRect.left += Math.min(...newCellsLefts); } newRect.height = (this.cellSize.height() + this.verticalSpacing()) * newVertical - this.verticalSpacing() - unitsToPixel(this._getBorderWidthBySpacing(this.verticalSpacing()) * (newVertical - 1), this._context.measureUnit(), 1); newRect.width = (this.cellSize.width() + this.horizontalSpacing()) * newHorizontal - this.horizontalSpacing() - unitsToPixel(this._getBorderWidthBySpacing(this.horizontalSpacing()) * (newHorizontal - 1), this._context.measureUnit(), 1); } updateArray(cellsCount, array) { const cells = array || this.cells.peek(); if (cells.length > cellsCount) { cells.splice(cellsCount, cells.length - cellsCount); } else if (cells.length < cellsCount) { for (let i = cells.length; i < cellsCount; i++) { cells.push(this._createCell('', i)); } } if (!array) this.cells.valueHasMutated(); } fitBoundsToText() { const _multiline = this._control['multiline'] && this._control['multiline'](); const _wordwrap = this._control['wordWrap'] && this._control['wordWrap'](); const zoom = this._context.zoom(); const oldRect = this.rect(); const newRect = {}; Object.keys(oldRect).forEach(propertyName => { newRect[propertyName] = oldRect[propertyName] / zoom; }); const newHorizVert = CharacterCombHelper.getHorizontalVerticalByText(_multiline, _wordwrap, this.displayText(), this.horizontal() || 1, this.vertical() || 1); this._applyBounds(newRect, newHorizVert.horizontal, newHorizVert.vertical, _multiline, _wordwrap); if (newRect.top !== oldRect.top || newRect.height !== oldRect.height || newRect.left !== oldRect.left || newRect.width !== oldRect.width) { this.rect({ top: Math.round(newRect.top * zoom), height: newRect.height * zoom, left: Math.round(newRect.left * zoom), width: newRect.width * zoom }); this.getControlModel().roundSize(); } } constructor(control, context) { super(control, context); this.cells = ko.observableArray([]); this._disposables.push(this.borderWidth = ko.computed(() => { return control['borderWidth']() === undefined ? 1 : control['borderWidth'](); })); this.rtl = () => { return control.rtl(); }; this.borders = control['borders']; this.template = 'dxrd-charactercomb'; this.contenttemplate = 'dxrd-charactercomb-content'; this._disposables.push(control.textAlignment.subscribe((newVal) => { this._updateCellsText(newVal); })); this._disposables.push(this.verticalSpacing = ko.computed(() => { return unitsToPixel(control.verticalSpacing(), context.measureUnit(), 1); })); this._disposables.push(this.horizontalSpacing = ko.computed(() => { return unitsToPixel(control.horizontalSpacing(), context.measureUnit(), 1); })); this.cellSize = { width: ko.computed(() => { return unitsToPixel(control.cellWidth() || control.autoCellSide(), context.measureUnit(), 1); }), height: ko.computed(() => { return unitsToPixel(control.cellHeight() || control.autoCellSide(), context.measureUnit(), 1); }), isPropertyDisabled: (name) => { return false; } }; this._disposables.push(this.cellSize.width); this._disposables.push(this.cellSize.height); this._disposables.push(this.fullCellHeight = ko.computed(() => { const _verticalSpacing = this.verticalSpacing(); let fullCellHeight = this.cellSize.height(); if (!!this.verticalSpacing()) { fullCellHeight += this.verticalSpacing(); } return fullCellHeight - this._getBorderWidthBySpacing(_verticalSpacing); })); this._disposables.push(this.fullCellWidth = ko.computed(() => { const _horizontalSpacing = this.horizontalSpacing.peek(); let fullCellWidth = this.cellSize.width(); if (!!this.horizontalSpacing()) { fullCellWidth += this.horizontalSpacing(); } return fullCellWidth - this._getBorderWidthBySpacing(_horizontalSpacing); })); this._disposables.push(this.vertical = ko.computed(() => { const _borderWidth = this._getBorderWidthBySpacing(this.verticalSpacing()) * context.zoom(); const fullCellHeight = this.fullCellHeight() * context.zoom(); let vertical = Math.floor(roundingXDecimals((this.rect().height - _borderWidth) / fullCellHeight)); if (roundingXDecimals(this.rect().height - (vertical * fullCellHeight + _borderWidth)) >= roundingXDecimals(this.cellSize.height() * context.zoom() - _borderWidth)) { vertical += 1; } return vertical; })); this._disposables.push(this.horizontal = ko.computed(() => { const _borderWidth = this._getBorderWidthBySpacing(this.horizontalSpacing()) * context.zoom(); const fullCellWidth = this.fullCellWidth() * context.zoom(); let horizontal = Math.floor(roundingXDecimals((this.rect().width - _borderWidth) / fullCellWidth)); if (roundingXDecimals(this.rect().width - (horizontal * fullCellWidth + _borderWidth)) >= roundingXDecimals(this.cellSize.width() * context.zoom() - _borderWidth)) { horizontal += 1; } return horizontal; })); this._disposables.push(this.topEmptySpace = ko.computed(() => { const _verticalSpacing = this.verticalSpacing(); const _borderWidth = this._getBorderWidthBySpacing(_verticalSpacing); const _emptySpace = this.rect().height / context.zoom() - (this.fullCellHeight() * this.vertical() - _verticalSpacing + _borderWidth); return CharacterCombHelper.distributionEmptySpace(_emptySpace, true, this.getControlModel().textAlignment()); })); this._disposables.push(this.leftEmptySpace = ko.computed(() => { const _horizontalSpacing = this.horizontalSpacing(); const _borderWidth = this._getBorderWidthBySpacing(_horizontalSpacing); const _emptySpace = this.rect().width / context.zoom() - (this.fullCellWidth() * this.horizontal() - _horizontalSpacing + _borderWidth); return CharacterCombHelper.distributionEmptySpace(_emptySpace, false, this.getControlModel().textAlignment()); })); this._disposables.push(this.css = ko.pureComputed(() => { return extend({}, this.cssCalculator.fontCss(), this.cssCalculator.foreColorCss(), this.cssCalculator.backGroundCss()); })); this._disposables.push(this.borderCss = ko.pureComputed(() => { return this.cssCalculator.borderCss(); })); this._disposables.push(ko.computed(() => { this.updateArray(this.vertical() * this.horizontal()); this._updateCellsText(control.textAlignment.peek()); })); this._disposables.push(control.text.subscribe((newVal) => { this._updateCellsText(control.textAlignment.peek()); })); } getText() { return this.displayText(); } }