UNPKG

devexpress-reporting

Version:

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

268 lines (267 loc) 12.2 kB
/** * DevExpress HTML/JS Reporting (viewer\widgets\pictureEditor\_painter.js) * Version: 24.2.6 * Build date: Mar 18, 2025 * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * License: https://www.devexpress.com/Support/EULAs/universal.xml */ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { ImageSizeMode, ImageAlignment, sizing, imageAlignment } from '../../editing/editingField'; import { ImagePainter } from './_imagePainter'; import { SignaturePainter } from './_signaturePainter'; import { $dx, $unwrap, getLocalization } from '@devexpress/analytics-core/analytics-internal-native'; import * as events from 'devextreme/events'; import { BaseRenderingModel, createViewModelGenerator, mutable } from '@devexpress/analytics-core/analytics-serializer-native'; import { PictureEditorActionProvider } from './_pictureEditorActionProvider'; import { getEnumValues } from '../../internal/_utils'; import { ImageEditingFieldViewModel } from '../../editing/models/imageEditingField'; export class Painter extends BaseRenderingModel { _getContextPoint(e) { const element = $unwrap(e.target); if (element.nodeName !== 'CANVAS') return; let zoom = this.getZoom(); let x, y; if (e.offsetX && e.offsetY) { zoom = this.hasSignature() ? 1 : zoom; x = e.offsetX / zoom; y = e.offsetY / zoom; } else { const rect = this._context.canvas.getBoundingClientRect(); x = (e.clientX - rect.left) / zoom; y = (e.clientY - rect.top) / zoom; } return { x, y }; } _addEvents() { const element = this.$element.get(0); events.on(element, 'dxpointerdown', this._pointerDownHandler); events.on(element, 'dxpointermove', this._pointerMoveHandler); events.on(element, 'dxpointerleave', this._pointerLeaveHandler); } _removeEvents() { const element = this.$element.get(0); events.off(element, 'dxpointerdown', this._pointerDownHandler); events.off(element, 'dxpointermove', this._pointerMoveHandler); events.off(element, 'dxpointerleave', this._pointerLeaveHandler); } _setCanvasSize(width, height) { this._context.canvas.setAttribute('width', width); this._context.canvas.setAttribute('height', height); } _cleanCanvas() { this._context.clearRect(0, 0, this._context.canvas.width, this._context.canvas.height); } _getColorValues() { const array = []; PictureEditorActionProvider.colors.forEach((item) => { array.push(createViewModelGenerator() .generateProperty('action', () => { this.lineColor = item; array.forEach(x => x.isSelected = this.lineColor === x.value); }) .generateProperty('isSelected', this.lineColor === item) .generateProperty('value', item) .getViewModel()); }); return array; } _getEnumValues(enumType, prefix, propertyName, info) { const array = []; getEnumValues(enumType).forEach((item) => { let attrTitle = undefined; if (info && info.valuesArray.length > 0) { const displayValue = info.valuesArray.filter((value) => value.value === item)[0]; attrTitle = getLocalization(displayValue.displayValue || displayValue.value, displayValue.localizationId); } array.push(createViewModelGenerator() .generateProperty('action', () => { this[propertyName] = enumType[item]; array.forEach(x => x.isSelected = this[propertyName] === enumType[x.value]); this.refresh(); }) .generateProperty('attrTitle', attrTitle) .generateProperty('iconTemplate', 'dxrd-svg-pictureeditor-' + prefix + '_' + item.toLowerCase()) .generateProperty('isSelected', this[propertyName] === enumType[item]) .generateProperty('value', item) .getViewModel()); }); return array; } constructor(element, options, onResize) { super(); this._pointerDownHandler = (e) => { const point = this._getContextPoint(e); point && this.signaturePainter.drawCircle(this._context, point.x, point.y, this.lineColor, this.lineWidth); }; this._pointerMoveHandler = (e) => { if (e.pointerType === 'touch' || e.pointerType === 'pen' || (e.pointerType === 'mouse' && e.originalEvent['buttons'] == 1)) { const point = this._getContextPoint(e); point && this.signaturePainter.drawPath(this._context, point.x, point.y, this.lineColor, this.lineWidth); } }; this._pointerLeaveHandler = (e) => { this.signaturePainter.resetLastPosition(); }; this.format = (newVal) => { if (newVal) this.imagePainter.format = newVal; return this.imagePainter.format; }; this.image = options.imageSource; this.imageSizeMode = options.sizeMode; this.imageAlignment = options.alignment; this.imagePainter = new ImagePainter({ alignment: () => this.imageAlignment, imageSource: () => this.image, sizeMode: () => this.imageSizeMode }); this.getZoom = () => options.editingFieldModel.zoom; this.format(options.imageType); this._disposables.push(this.signaturePainter = new SignaturePainter()); this.addDisposable(this.signaturePainter.events.on('hasPointsChanged', (args) => { if (args.newValue) this._setCanvasSize(this.initialSize.width, this.initialSize.height); else this._setCanvasSize(this.initialSize.width * this.getZoom(), this.initialSize.height * this.getZoom()); this.refresh(); this._updateScale(); })); this._updateScale = () => { this.scale = this.hasSignature() ? this.getZoom() : 1; onResize && onResize(); }; this._updateScale(); if (options.pictureEditorModel) { this.addDisposable(options.pictureEditorModel.events.on('canDrawChanged', (args) => { if (args.newValue) { this._addEvents(); } else { this._removeEvents(); } })); } this.addDisposable(options.editingFieldModel.events.on('zoomChanged', (args) => { const newVal = args.newValue; if (!this.signaturePainter.hasPoints) { this._setCanvasSize(this.initialSize.width * newVal, this.initialSize.height * newVal); this.refresh(); } this._updateScale(); })); this.initSize(element, options.editingFieldModel.zoom); this.initCanvas(options.editingFieldModel.zoom); } onPropertyChanged(args) { } createViewModel() { return createViewModelGenerator(super.createViewModel()) .generateProperty('scale', this.scale) .generateProperty('brushOptions', createViewModelGenerator() .generateProperty('lineWidth', this.lineWidth) .generateProperty('lineColor', this.lineColor) .generateProperty('colors', this._getColorValues()) .generateProperty('onLineWidthChanged', (event) => this.lineWidth = event.value) .generateProperty('brushWidthText', getLocalization('Brush size', 'PreviewStringId.ImageEditingFieldEditor_BrushSize')) .generateProperty('brushColorText', getLocalization('Brush color', 'PreviewStringId.ImageEditingFieldEditor_BrushColor')) .getViewModel()) .generateProperty('sizingOptions', createViewModelGenerator() .generateProperty('alignment', this.imageAlignment) .generateProperty('alignmentText', getLocalization('Alignment', 'PreviewStringId.ImageEditingFieldEditor_Alignment')) .generateProperty('alignmentValues', this._getEnumValues(ImageAlignment, 'alignment', 'imageAlignment', imageAlignment)) .generateProperty('sizeMode', this.imageSizeMode) .generateProperty('sizeModeText', getLocalization('Size Mode', 'PreviewStringId.ImageEditingFieldEditor_SizeMode')) .generateProperty('sizeModeValues', this._getEnumValues(ImageSizeMode, 'size_mode', 'imageSizeMode', sizing)) .getViewModel()) .getViewModel(); } updateViewModel(args) { const viewModel = this.getViewModel(); if (args.propertyName === 'lineWidth') viewModel.brushOptions.lineWidth = this.lineWidth; if (args.propertyName === 'lineColor') viewModel.brushOptions.lineColor = this.lineColor; if (args.propertyName === 'scale') viewModel.scale = this.scale; if (args.propertyName === 'imageAlignment') viewModel.sizingOptions.alignment = this.imageAlignment; if (args.propertyName === 'imageSizeMode') viewModel.sizingOptions.sizeMode = this.imageSizeMode; } clear() { this.image = null; this.signaturePainter.reset(); this._cleanCanvas(); } refresh() { this._cleanCanvas(); const zoom = this.signaturePainter.hasPoints ? 1 : this.getZoom(); const size = this.signaturePainter.hasPoints ? this.initialSize : undefined; this.imagePainter.refresh(this._context, zoom, size) .then(() => this.signaturePainter.refresh(this._context)); } initSize(element, zoom) { this.$element = $dx(element); this.initialSize = { width: this.$element.outerWidth() / zoom, height: this.$element.outerHeight() / zoom }; } initCanvas(zoom) { const canvas = this.$element.find('canvas')[0]; this._context = canvas.getContext('2d'); this._setCanvasSize(this.initialSize.width * zoom, this.initialSize.height * zoom); this.imagePainter.refresh(this._context, zoom, { width: this._context.canvas.offsetWidth, height: this._context.canvas.offsetHeight }); } imageFormatByType(imageType) { return imageType === ImageEditingFieldViewModel.__DefaultImageType ? 'png' : imageType; } getImage() { return this._context.canvas.toDataURL('image/png'); } hasSignature() { return this.signaturePainter.hasPoints; } dispose() { super.dispose(); this._removeEvents(); this.$element = null; this._context = null; this.getZoom = null; } reset(initialImage, initialAlignment, initialSizeMode, initialImageType) { this.image = initialImage; this.imageAlignment = initialAlignment; this.imageSizeMode = initialSizeMode; this.format(this.imageFormatByType(initialImageType)); this.signaturePainter.reset(); this.refresh(); } } __decorate([ mutable() ], Painter.prototype, "image", void 0); __decorate([ mutable(ImageSizeMode.Normal) ], Painter.prototype, "imageSizeMode", void 0); __decorate([ mutable(ImageAlignment.TopLeft) ], Painter.prototype, "imageAlignment", void 0); __decorate([ mutable() ], Painter.prototype, "scale", void 0); __decorate([ mutable(1) ], Painter.prototype, "lineWidth", void 0); __decorate([ mutable('#000000') ], Painter.prototype, "lineColor", void 0);