123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- /*!
- * ZRender, a high performance 2d drawing library.
- *
- * Copyright (c) 2013, Baidu Inc.
- * All rights reserved.
- *
- * LICENSE
- * https://github.com/ecomfe/zrender/blob/master/LICENSE.txt
- */
- import env from './core/env';
- import * as zrUtil from './core/util';
- import Handler from './Handler';
- import Storage from './Storage';
- import {PainterBase} from './PainterBase';
- import Animation, {getTime} from './animation/Animation';
- import HandlerProxy from './dom/HandlerProxy';
- import Element, { ElementEventCallback } from './Element';
- import { Dictionary, ElementEventName, RenderedEvent, WithThisType } from './core/types';
- import { LayerConfig } from './canvas/Layer';
- import { GradientObject } from './graphic/Gradient';
- import { PatternObject } from './graphic/Pattern';
- import { EventCallback } from './core/Eventful';
- import Displayable from './graphic/Displayable';
- import { lum } from './tool/color';
- import { DARK_MODE_THRESHOLD } from './config';
- import Group from './graphic/Group';
- type PainterBaseCtor = {
- new(dom: HTMLElement, storage: Storage, ...args: any[]): PainterBase
- }
- const painterCtors: Dictionary<PainterBaseCtor> = {};
- let instances: { [key: number]: ZRender } = {};
- function delInstance(id: number) {
- delete instances[id];
- }
- function isDarkMode(backgroundColor: string | GradientObject | PatternObject): boolean {
- if (!backgroundColor) {
- return false;
- }
- if (typeof backgroundColor === 'string') {
- return lum(backgroundColor, 1) < DARK_MODE_THRESHOLD;
- }
- else if ((backgroundColor as GradientObject).colorStops) {
- const colorStops = (backgroundColor as GradientObject).colorStops;
- let totalLum = 0;
- const len = colorStops.length;
- // Simply do the math of average the color. Not consider the offset
- for (let i = 0; i < len; i++) {
- totalLum += lum(colorStops[i].color, 1);
- }
- totalLum /= len;
- return totalLum < DARK_MODE_THRESHOLD;
- }
- // Can't determine
- return false;
- }
- class ZRender {
- /**
- * Not necessary if using SSR painter like svg-ssr
- */
- dom?: HTMLElement
- id: number
- storage: Storage
- painter: PainterBase
- handler: Handler
- animation: Animation
- private _sleepAfterStill = 10;
- private _stillFrameAccum = 0;
- private _needsRefresh = true
- private _needsRefreshHover = true
- /**
- * If theme is dark mode. It will determine the color strategy for labels.
- */
- private _darkMode = false;
- private _backgroundColor: string | GradientObject | PatternObject;
- constructor(id: number, dom?: HTMLElement, opts?: ZRenderInitOpt) {
- opts = opts || {};
- /**
- * @type {HTMLDomElement}
- */
- this.dom = dom;
- this.id = id;
- const storage = new Storage();
- let rendererType = opts.renderer || 'canvas';
- if (!painterCtors[rendererType]) {
- // Use the first registered renderer.
- rendererType = zrUtil.keys(painterCtors)[0];
- }
- if (process.env.NODE_ENV !== 'production') {
- if (!painterCtors[rendererType]) {
- throw new Error(`Renderer '${rendererType}' is not imported. Please import it first.`);
- }
- }
- opts.useDirtyRect = opts.useDirtyRect == null
- ? false
- : opts.useDirtyRect;
- const painter = new painterCtors[rendererType](dom, storage, opts, id);
- const ssrMode = opts.ssr || painter.ssrOnly;
- this.storage = storage;
- this.painter = painter;
- const handerProxy = (!env.node && !env.worker && !ssrMode)
- ? new HandlerProxy(painter.getViewportRoot(), painter.root)
- : null;
- const useCoarsePointer = opts.useCoarsePointer;
- const usePointerSize = (useCoarsePointer == null || useCoarsePointer === 'auto')
- ? env.touchEventsSupported
- : !!useCoarsePointer;
- const defaultPointerSize = 44;
- let pointerSize;
- if (usePointerSize) {
- pointerSize = zrUtil.retrieve2(opts.pointerSize, defaultPointerSize);
- }
- this.handler = new Handler(storage, painter, handerProxy, painter.root, pointerSize);
- this.animation = new Animation({
- stage: {
- update: ssrMode ? null : () => this._flush(true)
- }
- });
- if (!ssrMode) {
- this.animation.start();
- }
- }
- /**
- * 添加元素
- */
- add(el: Element) {
- if (!el) {
- return;
- }
- this.storage.addRoot(el);
- el.addSelfToZr(this);
- this.refresh();
- }
- /**
- * 删除元素
- */
- remove(el: Element) {
- if (!el) {
- return;
- }
- this.storage.delRoot(el);
- el.removeSelfFromZr(this);
- this.refresh();
- }
- /**
- * Change configuration of layer
- */
- configLayer(zLevel: number, config: LayerConfig) {
- if (this.painter.configLayer) {
- this.painter.configLayer(zLevel, config);
- }
- this.refresh();
- }
- /**
- * Set background color
- */
- setBackgroundColor(backgroundColor: string | GradientObject | PatternObject) {
- if (this.painter.setBackgroundColor) {
- this.painter.setBackgroundColor(backgroundColor);
- }
- this.refresh();
- this._backgroundColor = backgroundColor;
- this._darkMode = isDarkMode(backgroundColor);
- }
- getBackgroundColor() {
- return this._backgroundColor;
- }
- /**
- * Force to set dark mode
- */
- setDarkMode(darkMode: boolean) {
- this._darkMode = darkMode;
- }
- isDarkMode() {
- return this._darkMode;
- }
- /**
- * Repaint the canvas immediately
- */
- refreshImmediately(fromInside?: boolean) {
- // const start = new Date();
- if (!fromInside) {
- // Update animation if refreshImmediately is invoked from outside.
- // Not trigger stage update to call flush again. Which may refresh twice
- this.animation.update(true);
- }
- // Clear needsRefresh ahead to avoid something wrong happens in refresh
- // Or it will cause zrender refreshes again and again.
- this._needsRefresh = false;
- this.painter.refresh();
- // Avoid trigger zr.refresh in Element#beforeUpdate hook
- this._needsRefresh = false;
- }
- /**
- * Mark and repaint the canvas in the next frame of browser
- */
- refresh() {
- this._needsRefresh = true;
- // Active the animation again.
- this.animation.start();
- }
- /**
- * Perform all refresh
- */
- flush() {
- this._flush(false);
- }
- private _flush(fromInside?: boolean) {
- let triggerRendered;
- const start = getTime();
- if (this._needsRefresh) {
- triggerRendered = true;
- this.refreshImmediately(fromInside);
- }
- if (this._needsRefreshHover) {
- triggerRendered = true;
- this.refreshHoverImmediately();
- }
- const end = getTime();
- if (triggerRendered) {
- this._stillFrameAccum = 0;
- this.trigger('rendered', {
- elapsedTime: end - start
- } as RenderedEvent);
- }
- else if (this._sleepAfterStill > 0) {
- this._stillFrameAccum++;
- // Stop the animiation after still for 10 frames.
- if (this._stillFrameAccum > this._sleepAfterStill) {
- this.animation.stop();
- }
- }
- }
- /**
- * Set sleep after still for frames.
- * Disable auto sleep when it's 0.
- */
- setSleepAfterStill(stillFramesCount: number) {
- this._sleepAfterStill = stillFramesCount;
- }
- /**
- * Wake up animation loop. But not render.
- */
- wakeUp() {
- this.animation.start();
- // Reset the frame count.
- this._stillFrameAccum = 0;
- }
- /**
- * Refresh hover in next frame
- */
- refreshHover() {
- this._needsRefreshHover = true;
- }
- /**
- * Refresh hover immediately
- */
- refreshHoverImmediately() {
- this._needsRefreshHover = false;
- if (this.painter.refreshHover && this.painter.getType() === 'canvas') {
- this.painter.refreshHover();
- }
- }
- /**
- * Resize the canvas.
- * Should be invoked when container size is changed
- */
- resize(opts?: {
- width?: number| string
- height?: number | string
- }) {
- opts = opts || {};
- this.painter.resize(opts.width, opts.height);
- this.handler.resize();
- }
- /**
- * Stop and clear all animation immediately
- */
- clearAnimation() {
- this.animation.clear();
- }
- /**
- * Get container width
- */
- getWidth(): number {
- return this.painter.getWidth();
- }
- /**
- * Get container height
- */
- getHeight(): number {
- return this.painter.getHeight();
- }
- /**
- * Set default cursor
- * @param cursorStyle='default' 例如 crosshair
- */
- setCursorStyle(cursorStyle: string) {
- this.handler.setCursorStyle(cursorStyle);
- }
- /**
- * Find hovered element
- * @param x
- * @param y
- * @return {target, topTarget}
- */
- findHover(x: number, y: number): {
- target: Displayable
- topTarget: Displayable
- } {
- return this.handler.findHover(x, y);
- }
- on<Ctx>(eventName: ElementEventName, eventHandler: ElementEventCallback<Ctx, ZRenderType>, context?: Ctx): this
- // eslint-disable-next-line max-len
- on<Ctx>(eventName: string, eventHandler: WithThisType<EventCallback<any[]>, unknown extends Ctx ? ZRenderType : Ctx>, context?: Ctx): this
- // eslint-disable-next-line max-len
- on<Ctx>(eventName: string, eventHandler: (...args: any) => any, context?: Ctx): this {
- this.handler.on(eventName, eventHandler, context);
- return this;
- }
- /**
- * Unbind event
- * @param eventName Event name
- * @param eventHandler Handler function
- */
- // eslint-disable-next-line max-len
- off(eventName?: string, eventHandler?: EventCallback) {
- this.handler.off(eventName, eventHandler);
- }
- /**
- * Trigger event manually
- *
- * @param eventName Event name
- * @param event Event object
- */
- trigger(eventName: string, event?: unknown) {
- this.handler.trigger(eventName, event);
- }
- /**
- * Clear all objects and the canvas.
- */
- clear() {
- const roots = this.storage.getRoots();
- for (let i = 0; i < roots.length; i++) {
- if (roots[i] instanceof Group) {
- roots[i].removeSelfFromZr(this);
- }
- }
- this.storage.delAllRoots();
- this.painter.clear();
- }
- /**
- * Dispose self.
- */
- dispose() {
- this.animation.stop();
- this.clear();
- this.storage.dispose();
- this.painter.dispose();
- this.handler.dispose();
- this.animation =
- this.storage =
- this.painter =
- this.handler = null;
- delInstance(this.id);
- }
- }
- export interface ZRenderInitOpt {
- renderer?: string // 'canvas' or 'svg
- devicePixelRatio?: number
- width?: number | string // 10, 10px, 'auto'
- height?: number | string
- useDirtyRect?: boolean
- useCoarsePointer?: 'auto' | boolean
- pointerSize?: number
- ssr?: boolean // If enable ssr mode.
- }
- /**
- * Initializing a zrender instance
- *
- * @param dom Not necessary if using SSR painter like svg-ssr
- */
- export function init(dom?: HTMLElement | null, opts?: ZRenderInitOpt) {
- const zr = new ZRender(zrUtil.guid(), dom, opts);
- instances[zr.id] = zr;
- return zr;
- }
- /**
- * Dispose zrender instance
- */
- export function dispose(zr: ZRender) {
- zr.dispose();
- }
- /**
- * Dispose all zrender instances
- */
- export function disposeAll() {
- for (let key in instances) {
- if (instances.hasOwnProperty(key)) {
- instances[key].dispose();
- }
- }
- instances = {};
- }
- /**
- * Get zrender instance by id
- */
- export function getInstance(id: number): ZRender {
- return instances[id];
- }
- export function registerPainter(name: string, Ctor: PainterBaseCtor) {
- painterCtors[name] = Ctor;
- }
- /**
- * @type {string}
- */
- export const version = '5.4.3';
- export interface ZRenderType extends ZRender {};
|