Path: blob/main/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { FastDomNode, createFastDomNode } from '../../../../base/browser/fastDomNode.js';6import { IOverviewRuler } from '../../editorBrowser.js';7import { OverviewRulerPosition, EditorOption } from '../../../common/config/editorOptions.js';8import { ColorZone, OverviewRulerZone, OverviewZoneManager } from '../../../common/viewModel/overviewZoneManager.js';9import { ViewContext } from '../../../common/viewModel/viewContext.js';10import * as viewEvents from '../../../common/viewEvents.js';11import { ViewEventHandler } from '../../../common/viewEventHandler.js';1213/**14* The overview ruler appears underneath the editor scroll bar and shows things15* like the cursor, various decorations, etc.16*/17export class OverviewRuler extends ViewEventHandler implements IOverviewRuler {1819private readonly _context: ViewContext;20private readonly _domNode: FastDomNode<HTMLCanvasElement>;21private readonly _zoneManager: OverviewZoneManager;2223constructor(context: ViewContext, cssClassName: string) {24super();25this._context = context;26const options = this._context.configuration.options;2728this._domNode = createFastDomNode(document.createElement('canvas'));29this._domNode.setClassName(cssClassName);30this._domNode.setPosition('absolute');31this._domNode.setLayerHinting(true);32this._domNode.setContain('strict');3334this._zoneManager = new OverviewZoneManager((lineNumber: number) => this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber));35this._zoneManager.setDOMWidth(0);36this._zoneManager.setDOMHeight(0);37this._zoneManager.setOuterHeight(this._context.viewLayout.getScrollHeight());38this._zoneManager.setLineHeight(options.get(EditorOption.lineHeight));3940this._zoneManager.setPixelRatio(options.get(EditorOption.pixelRatio));4142this._context.addEventHandler(this);43}4445public override dispose(): void {46this._context.removeEventHandler(this);47super.dispose();48}4950// ---- begin view event handlers5152public override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {53const options = this._context.configuration.options;5455if (e.hasChanged(EditorOption.lineHeight)) {56this._zoneManager.setLineHeight(options.get(EditorOption.lineHeight));57this._render();58}5960if (e.hasChanged(EditorOption.pixelRatio)) {61this._zoneManager.setPixelRatio(options.get(EditorOption.pixelRatio));62this._domNode.setWidth(this._zoneManager.getDOMWidth());63this._domNode.setHeight(this._zoneManager.getDOMHeight());64this._domNode.domNode.width = this._zoneManager.getCanvasWidth();65this._domNode.domNode.height = this._zoneManager.getCanvasHeight();66this._render();67}6869return true;70}71public override onFlushed(e: viewEvents.ViewFlushedEvent): boolean {72this._render();73return true;74}75public override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {76if (e.scrollHeightChanged) {77this._zoneManager.setOuterHeight(e.scrollHeight);78this._render();79}80return true;81}82public override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {83this._render();84return true;85}8687// ---- end view event handlers8889public getDomNode(): HTMLElement {90return this._domNode.domNode;91}9293public setLayout(position: OverviewRulerPosition): void {94this._domNode.setTop(position.top);95this._domNode.setRight(position.right);9697let hasChanged = false;98hasChanged = this._zoneManager.setDOMWidth(position.width) || hasChanged;99hasChanged = this._zoneManager.setDOMHeight(position.height) || hasChanged;100101if (hasChanged) {102this._domNode.setWidth(this._zoneManager.getDOMWidth());103this._domNode.setHeight(this._zoneManager.getDOMHeight());104this._domNode.domNode.width = this._zoneManager.getCanvasWidth();105this._domNode.domNode.height = this._zoneManager.getCanvasHeight();106107this._render();108}109}110111public setZones(zones: OverviewRulerZone[]): void {112this._zoneManager.setZones(zones);113this._render();114}115116private _render(): boolean {117if (this._zoneManager.getOuterHeight() === 0) {118return false;119}120121const width = this._zoneManager.getCanvasWidth();122const height = this._zoneManager.getCanvasHeight();123124const colorZones = this._zoneManager.resolveColorZones();125const id2Color = this._zoneManager.getId2Color();126127const ctx = this._domNode.domNode.getContext('2d')!;128ctx.clearRect(0, 0, width, height);129if (colorZones.length > 0) {130this._renderOneLane(ctx, colorZones, id2Color, width);131}132133return true;134}135136private _renderOneLane(ctx: CanvasRenderingContext2D, colorZones: ColorZone[], id2Color: string[], width: number): void {137138let currentColorId = 0;139let currentFrom = 0;140let currentTo = 0;141142for (const zone of colorZones) {143144const zoneColorId = zone.colorId;145const zoneFrom = zone.from;146const zoneTo = zone.to;147148if (zoneColorId !== currentColorId) {149ctx.fillRect(0, currentFrom, width, currentTo - currentFrom);150151currentColorId = zoneColorId;152ctx.fillStyle = id2Color[currentColorId];153currentFrom = zoneFrom;154currentTo = zoneTo;155} else {156if (currentTo >= zoneFrom) {157currentTo = Math.max(currentTo, zoneTo);158} else {159ctx.fillRect(0, currentFrom, width, currentTo - currentFrom);160currentFrom = zoneFrom;161currentTo = zoneTo;162}163}164}165166ctx.fillRect(0, currentFrom, width, currentTo - currentFrom);167168}169}170171172