981377660LMT / ts

ts学习
6 stars 1 forks source link

zrender core 分析 #330

Open 981377660LMT opened 1 year ago

981377660LMT commented 1 year ago

types 文件夹

/** 普通对象. */
export type Dictionary<T> = {
  [key: string]: T
}

/**
 * Not readonly ArrayLike
 * Include Array, TypedArray
 */
export type ArrayLike<T> = {
  [key: number]: T
  length: number
}

export type ImageLike = HTMLImageElement | HTMLCanvasElement | HTMLVideoElement

// subset of CanvasTextBaseline
export type TextVerticalAlign = 'top' | 'middle' | 'bottom'
// | 'center' // DEPRECATED

// TODO: Have not support 'start', 'end' yet.
// subset of CanvasTextAlign
export type TextAlign = 'left' | 'center' | 'right'
// | 'middle' // DEPRECATED

export type FontWeight = 'normal' | 'bold' | 'bolder' | 'lighter' | number
export type FontStyle = 'normal' | 'italic' | 'oblique'

export type BuiltinTextPosition =
  | 'left'
  | 'right'
  | 'top'
  | 'bottom'
  | 'inside'
  | 'insideLeft'
  | 'insideRight'
  | 'insideTop'
  | 'insideBottom'
  | 'insideTopLeft'
  | 'insideTopRight'
  | 'insideBottomLeft'
  | 'insideBottomRight'

export type WXCanvasRenderingContext = CanvasRenderingContext2D & {
  draw: () => void
}

export type ZRCanvasRenderingContext = CanvasRenderingContext2D & {
  dpr: number
  __attrCachedBy: boolean | number
}

// #region 扩展事件属性

// Properties zrender will extended to the raw event
type ZREventProperties = {
  zrX: number
  zrY: number
  zrDelta: number

  // 'no_globalout' means: do not trigger "globalout" event to zr user.
  // 'only_globalout" means: only trigger "globalout" event, but do not
  //     trigger other event to zr user.
  zrEventControl: 'no_globalout' | 'only_globalout'

  zrByTouch: boolean
}

export type ZRRawMouseEvent = MouseEvent & ZREventProperties
export type ZRRawTouchEvent = TouchEvent & ZREventProperties
export type ZRRawPointerEvent = TouchEvent & ZREventProperties

export type ZRRawEvent = ZRRawMouseEvent | ZRRawTouchEvent | ZRRawPointerEvent

export type ZRPinchEvent = ZRRawEvent & {
  pinchScale: number
  pinchX: number
  pinchY: number
  gestureEvent: string
}

// #endregion

export type ElementEventName =
  | 'click'
  | 'dblclick'
  | 'mousewheel'
  | 'mouseout'
  | 'mouseover'
  | 'mouseup'
  | 'mousedown'
  | 'mousemove'
  | 'contextmenu'
  | 'drag'
  | 'dragstart'
  | 'dragend'
  | 'dragenter'
  | 'dragleave'
  | 'dragover'
  | 'drop'
  | 'globalout'

export type ElementEventNameWithOn =
  | 'onclick'
  | 'ondblclick'
  | 'onmousewheel'
  | 'onmouseout'
  | 'onmouseup'
  | 'onmousedown'
  | 'onmousemove'
  | 'oncontextmenu'
  | 'ondrag'
  | 'ondragstart'
  | 'ondragend'
  | 'ondragenter'
  | 'ondragleave'
  | 'ondragover'
  | 'ondrop'

// Useful type methods
export type PropType<TObj, TProp extends keyof TObj> = TObj[TProp]

export type AllPropTypes<T> = PropType<T, keyof T>

export type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]

// 将 T 中的所有属性值类型映射为 S 类型,如果属性值本身还是一个 Dictionary<any> 类型,那么会递归地进行映射。
export type MapToType<T extends Dictionary<any>, S> = {
  [P in keyof T]: T[P] extends Dictionary<any> ? MapToType<T[P], S> : S
}

// See https://www.staging-typescript.org/docs/handbook/advanced-types.html#distributive-conditional-types
// For the case:
// `keyof A | B` does not equals to `Keyof A | Keyof B`
// KeyOfDistributive<A | B> equals to `KeyOfDistributive<A> | KeyOfDistributive<B>`
export type KeyOfDistributive<T> = T extends unknown ? keyof T : never

export type WithThisType<Func extends (...args: any) => any, This> = (
  this: This,
  ...args: Parameters<Func>
) => ReturnType<Func>
981377660LMT commented 1 year ago

env

// 这段代码主要用于检测和识别运行环境,包括浏览器类型、版本、是否支持 SVG、触摸事件、指针事件、DOM、2D/3D 变换等。代码首先定义了两个类 Browser 和 Env,然后创建了一个 Env 类的实例 env,接着根据不同的运行环境进行检测和设置相应的属性。

// 首先判断是否在微信小程序环境中,如果是,则设置 env.wxa 为 true,并设置 env.touchEventsSupported 为 true。
// 接着判断是否在 Web Worker 环境中,如果是,则设置 env.worker 为 true。
// 然后判断是否在 Node.js 环境中,如果是,则设置 env.node 为 true,并设置 env.svgSupported 为 true。
// 最后,如果都不是以上环境,则认为是在浏览器环境中,调用 detect 函数进行浏览器类型和版本的检测。
// detect 函数主要通过分析 navigator.userAgent 字符串来识别浏览器类型和版本。具体步骤如下:

// 通过正则表达式匹配 Firefox、IE、Edge 和 WeChat 的版本信息。
// 根据匹配结果,设置 env.browser 的相关属性,如 firefox、ie、edge、newEdge 和 weChat。
// 判断是否支持 SVG,如果 SVGRect 存在,则设置 env.svgSupported 为 true。
// 判断是否支持触摸事件,如果 ontouchstart 存在于 window 对象中且不是 IE 和 Edge 浏览器,则设置 env.touchEventsSupported 为 true。
// 判断是否支持指针事件,如果 onpointerdown 存在于 window 对象中且是 Edge 或 IE11+ 浏览器,则设置 env.pointerEventsSupported 为 true。
// 判断是否支持 DOM,如果 document 存在,则设置 env.domSupported 为 true。
// 判断是否支持 3D 变换,根据不同浏览器的特性进行判断,如 IE9+、Edge、WebKit 和 Gecko 等,设置 env.transform3dSupported。
// 判断是否支持 2D 变换,如果支持 3D 变换或者是 IE9+ 浏览器,则设置 env.transformSupported 为 true。
// 最后,将 env 对象导出,供其他模块使用。

declare const wx: {
  getSystemInfoSync: Function
}

class Browser {
  firefox = false
  ie = false
  edge = false
  newEdge = false
  weChat = false
  version: string | number
}

class Env {
  browser = new Browser()
  node = false
  wxa = false
  worker = false

  svgSupported = false
  touchEventsSupported = false
  pointerEventsSupported = false
  domSupported = false
  transformSupported = false
  transform3dSupported = false

  hasGlobalWindow = typeof window !== 'undefined'
}

const env = new Env()

if (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {
  env.wxa = true
  env.touchEventsSupported = true
} else if (typeof document === 'undefined' && typeof self !== 'undefined') {
  // In worker
  env.worker = true
} else if (typeof navigator === 'undefined') {
  // In node
  env.node = true
  env.svgSupported = true
} else {
  detect(navigator.userAgent, env)
}

// Zepto.js
// (c) 2010-2013 Thomas Fuchs
// Zepto.js may be freely distributed under the MIT license.

function detect(ua: string, env: Env) {
  const browser = env.browser
  const firefox = ua.match(/Firefox\/([\d.]+)/)
  const ie =
    ua.match(/MSIE\s([\d.]+)/) ||
    // IE 11 Trident/7.0; rv:11.0
    ua.match(/Trident\/.+?rv:(([\d.]+))/)
  const edge = ua.match(/Edge?\/([\d.]+)/) // IE 12 and 12+

  const weChat = /micromessenger/i.test(ua)

  if (firefox) {
    browser.firefox = true
    browser.version = firefox[1]
  }
  if (ie) {
    browser.ie = true
    browser.version = ie[1]
  }

  if (edge) {
    browser.edge = true
    browser.version = edge[1]
    browser.newEdge = +edge[1].split('.')[0] > 18
  }

  // It is difficult to detect WeChat in Win Phone precisely, because ua can
  // not be set on win phone. So we do not consider Win Phone.
  if (weChat) {
    browser.weChat = true
  }

  env.svgSupported = typeof SVGRect !== 'undefined'
  env.touchEventsSupported = 'ontouchstart' in window && !browser.ie && !browser.edge
  env.pointerEventsSupported = 'onpointerdown' in window && (browser.edge || (browser.ie && +browser.version >= 11))
  env.domSupported = typeof document !== 'undefined'

  const style = document.documentElement.style

  env.transform3dSupported =
    // IE9 only supports transform 2D
    // transform 3D supported since IE10
    // we detect it by whether 'transition' is in style
    ((browser.ie && 'transition' in style) ||
      // edge
      browser.edge ||
      // webkit
      ('WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix()) ||
      // gecko-based browsers
      'MozPerspective' in style) && // Opera supports CSS transforms after version 12
    !('OTransition' in style)

  // except IE 6-8 and very old firefox 2-3 & opera 10.1
  // other browsers all support `transform`
  env.transformSupported =
    env.transform3dSupported ||
    // transform 2D is supported in IE9
    (browser.ie && +browser.version >= 9)
}

export default env