Spaces:
Running
Running
| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| import * as zrUtil from 'zrender/src/core/util'; | |
| import * as graphic from '../../util/graphic'; | |
| import {getECData} from '../../util/innerStore'; | |
| import {createTextStyle} from '../../label/labelStyle'; | |
| import {getLayoutRect} from '../../util/layout'; | |
| import ComponentModel from '../../model/Component'; | |
| import { | |
| ComponentOption, | |
| BoxLayoutOptionMixin, | |
| ZRTextAlign, | |
| ZRTextVerticalAlign, | |
| ZRColor, | |
| BorderOptionMixin, | |
| LabelOption | |
| } from '../../util/types'; | |
| import ComponentView from '../../view/Component'; | |
| import GlobalModel from '../../model/Global'; | |
| import ExtensionAPI from '../../core/ExtensionAPI'; | |
| import {windowOpen} from '../../util/format'; | |
| import { EChartsExtensionInstallRegisters } from '../../extension'; | |
| export interface TitleOption extends ComponentOption, BoxLayoutOptionMixin, BorderOptionMixin { | |
| mainType?: 'title' | |
| show?: boolean | |
| text?: string | |
| /** | |
| * Link to url | |
| */ | |
| link?: string | |
| target?: 'self' | 'blank' | |
| subtext?: string | |
| sublink?: string | |
| subtarget?: 'self' | 'blank' | |
| textAlign?: ZRTextAlign | |
| textVerticalAlign?: ZRTextVerticalAlign | |
| /** | |
| * @deprecated Use textVerticalAlign instead | |
| */ | |
| textBaseline?: ZRTextVerticalAlign | |
| backgroundColor?: ZRColor | |
| /** | |
| * Padding between text and border. | |
| * Support to be a single number or an array. | |
| */ | |
| padding?: number | number[] | |
| /** | |
| * Gap between text and subtext | |
| */ | |
| itemGap?: number | |
| textStyle?: LabelOption | |
| subtextStyle?: LabelOption | |
| /** | |
| * If trigger mouse or touch event | |
| */ | |
| triggerEvent?: boolean | |
| /** | |
| * Radius of background border. | |
| */ | |
| borderRadius?: number | number[] | |
| } | |
| class TitleModel extends ComponentModel<TitleOption> { | |
| static type = 'title' as const; | |
| type = TitleModel.type; | |
| readonly layoutMode = {type: 'box', ignoreSize: true} as const; | |
| static defaultOption: TitleOption = { | |
| // zlevel: 0, | |
| z: 6, | |
| show: true, | |
| text: '', | |
| target: 'blank', | |
| subtext: '', | |
| subtarget: 'blank', | |
| left: 0, | |
| top: 0, | |
| backgroundColor: 'rgba(0,0,0,0)', | |
| borderColor: '#ccc', | |
| borderWidth: 0, | |
| padding: 5, | |
| itemGap: 10, | |
| textStyle: { | |
| fontSize: 18, | |
| fontWeight: 'bold', | |
| color: '#464646' | |
| }, | |
| subtextStyle: { | |
| fontSize: 12, | |
| color: '#6E7079' | |
| } | |
| }; | |
| } | |
| // View | |
| class TitleView extends ComponentView { | |
| static type = 'title' as const; | |
| type = TitleView.type; | |
| render(titleModel: TitleModel, ecModel: GlobalModel, api: ExtensionAPI) { | |
| this.group.removeAll(); | |
| if (!titleModel.get('show')) { | |
| return; | |
| } | |
| const group = this.group; | |
| const textStyleModel = titleModel.getModel('textStyle'); | |
| const subtextStyleModel = titleModel.getModel('subtextStyle'); | |
| let textAlign = titleModel.get('textAlign'); | |
| let textVerticalAlign = zrUtil.retrieve2( | |
| titleModel.get('textBaseline'), titleModel.get('textVerticalAlign') | |
| ); | |
| const textEl = new graphic.Text({ | |
| style: createTextStyle(textStyleModel, { | |
| text: titleModel.get('text'), | |
| fill: textStyleModel.getTextColor() | |
| }, {disableBox: true}), | |
| z2: 10 | |
| }); | |
| const textRect = textEl.getBoundingRect(); | |
| const subText = titleModel.get('subtext'); | |
| const subTextEl = new graphic.Text({ | |
| style: createTextStyle(subtextStyleModel, { | |
| text: subText, | |
| fill: subtextStyleModel.getTextColor(), | |
| y: textRect.height + titleModel.get('itemGap'), | |
| verticalAlign: 'top' | |
| }, {disableBox: true}), | |
| z2: 10 | |
| }); | |
| const link = titleModel.get('link'); | |
| const sublink = titleModel.get('sublink'); | |
| const triggerEvent = titleModel.get('triggerEvent', true); | |
| textEl.silent = !link && !triggerEvent; | |
| subTextEl.silent = !sublink && !triggerEvent; | |
| if (link) { | |
| textEl.on('click', function () { | |
| windowOpen(link, '_' + titleModel.get('target')); | |
| }); | |
| } | |
| if (sublink) { | |
| subTextEl.on('click', function () { | |
| windowOpen(sublink, '_' + titleModel.get('subtarget')); | |
| }); | |
| } | |
| getECData(textEl).eventData = getECData(subTextEl).eventData = triggerEvent | |
| ? { | |
| componentType: 'title', | |
| componentIndex: titleModel.componentIndex | |
| } | |
| : null; | |
| group.add(textEl); | |
| subText && group.add(subTextEl); | |
| // If no subText, but add subTextEl, there will be an empty line. | |
| let groupRect = group.getBoundingRect(); | |
| const layoutOption = titleModel.getBoxLayoutParams(); | |
| layoutOption.width = groupRect.width; | |
| layoutOption.height = groupRect.height; | |
| const layoutRect = getLayoutRect( | |
| layoutOption, { | |
| width: api.getWidth(), | |
| height: api.getHeight() | |
| }, titleModel.get('padding') | |
| ); | |
| // Adjust text align based on position | |
| if (!textAlign) { | |
| // Align left if title is on the left. center and right is same | |
| textAlign = (titleModel.get('left') || titleModel.get('right')) as ZRTextAlign; | |
| // @ts-ignore | |
| if (textAlign === 'middle') { | |
| textAlign = 'center'; | |
| } | |
| // Adjust layout by text align | |
| if (textAlign === 'right') { | |
| layoutRect.x += layoutRect.width; | |
| } | |
| else if (textAlign === 'center') { | |
| layoutRect.x += layoutRect.width / 2; | |
| } | |
| } | |
| if (!textVerticalAlign) { | |
| textVerticalAlign = (titleModel.get('top') || titleModel.get('bottom')) as ZRTextVerticalAlign; | |
| // @ts-ignore | |
| if (textVerticalAlign === 'center') { | |
| textVerticalAlign = 'middle'; | |
| } | |
| if (textVerticalAlign === 'bottom') { | |
| layoutRect.y += layoutRect.height; | |
| } | |
| else if (textVerticalAlign === 'middle') { | |
| layoutRect.y += layoutRect.height / 2; | |
| } | |
| textVerticalAlign = textVerticalAlign || 'top'; | |
| } | |
| group.x = layoutRect.x; | |
| group.y = layoutRect.y; | |
| group.markRedraw(); | |
| const alignStyle = { | |
| align: textAlign, | |
| verticalAlign: textVerticalAlign | |
| }; | |
| textEl.setStyle(alignStyle); | |
| subTextEl.setStyle(alignStyle); | |
| // Render background | |
| // Get groupRect again because textAlign has been changed | |
| groupRect = group.getBoundingRect(); | |
| const padding = layoutRect.margin; | |
| const style = titleModel.getItemStyle(['color', 'opacity']); | |
| style.fill = titleModel.get('backgroundColor'); | |
| const rect = new graphic.Rect({ | |
| shape: { | |
| x: groupRect.x - padding[3], | |
| y: groupRect.y - padding[0], | |
| width: groupRect.width + padding[1] + padding[3], | |
| height: groupRect.height + padding[0] + padding[2], | |
| r: titleModel.get('borderRadius') | |
| }, | |
| style: style, | |
| subPixelOptimize: true, | |
| silent: true | |
| }); | |
| group.add(rect); | |
| } | |
| } | |
| export function install(registers: EChartsExtensionInstallRegisters) { | |
| registers.registerComponentModel(TitleModel); | |
| registers.registerComponentView(TitleView); | |
| } |