diff --git a/.github/workflows/nightly-next.yaml b/.github/workflows/nightly-next.yaml new file mode 100644 index 000000000..1305fb47f --- /dev/null +++ b/.github/workflows/nightly-next.yaml @@ -0,0 +1,34 @@ +name: Publish Nightly Next + +on: + schedule: + - cron: '0 8 * * *' + workflow_dispatch: {} + repository_dispatch: + types: publish-nightly-next + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [12.x] + + steps: + - uses: actions/checkout@v2 + with: + ref: next + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + registry-url: https://registry.npmjs.org/ + - name: Setup and publish nightly + run: | + npm ci + npm run release + npm run prepare:nightly-next + npm publish --tag next + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} diff --git a/build/prepareNightly.js b/build/prepareNightly.js index e9e07739f..c2dd21dbc 100644 --- a/build/prepareNightly.js +++ b/build/prepareNightly.js @@ -2,26 +2,36 @@ const fs = require('fs'); const packageJsonPath = __dirname + '/../package.json'; const nightlyPackageName = 'zrender-nightly'; -const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); -const version = packageJson.version; -const parts = /(\d+)\.(\d+)\.(\d+)($|\-)/.exec(version); -if (!parts) { - throw new Error(`Invalid version number ${version}`); -} -// Add date to version. -const major = +parts[1]; -const minor = +parts[2]; -let patch = +parts[3]; -const isStable = !parts[4]; -if (isStable) { - // It's previous stable version. Dev version should be higher. - patch++; +function updateVersion(version) { + const isNext = process.argv.includes('--next'); + const parts = /(\d+)\.(\d+)\.(\d+)($|\-)/.exec(version); + if (!parts) { + throw new Error(`Invalid version number ${version}`); + } + // Add date to version. + const major = +parts[1]; + let minor = +parts[2]; + let patch = +parts[3]; + const isStable = !parts[4]; + if (isStable) { + // It's previous stable version. Dev version should be higher. + if (isNext) { + // Increase minor version for next branch. + minor++; + } + else { + // Increase main version for master branch. + patch++; + } + } + + const date = new Date().toISOString().replace(/:|T|\.|-/g, '').slice(0, 8); + return `${major}.${minor}.${patch}-dev.${date}`; } -const date = new Date().toISOString().replace(/:|T|\.|-/g, '').slice(0, 8); -const nightlyVersion = `${major}.${minor}.${patch}-dev.${date}`; +const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); packageJson.name = nightlyPackageName; -packageJson.version = nightlyVersion; +packageJson.version = updateVersion(packageJson.version); fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf-8'); \ No newline at end of file diff --git a/package.json b/package.json index e7c51bb37..2363a7c6d 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "build": "npm run build:bundle && npm run build:lib", "release": "node build/build.js --minify && npm run build:lib", "prepare:nightly": "node build/prepareNightly.js", + "prepare:nightly-next": "node build/prepareNightly.js --next", "build:bundle": "node build/build.js", "build:lib": "npx tsc -m ES2015 --outDir lib", "watch:bundle": "node build/build.js --watch", @@ -51,4 +52,4 @@ "typescript": "4.3.5", "uglify-js": "^3.10.0" } -} +} \ No newline at end of file diff --git a/src/Element.ts b/src/Element.ts index 0f75e67fb..633ad290a 100644 --- a/src/Element.ts +++ b/src/Element.ts @@ -28,7 +28,7 @@ import Point from './core/Point'; import { LIGHT_LABEL_COLOR, DARK_LABEL_COLOR } from './config'; import { parse, stringify } from './tool/color'; import env from './core/env'; -import { REDARAW_BIT } from './graphic/constants'; +import { REDRAW_BIT } from './graphic/constants'; export interface ElementAnimateConfig { duration?: number @@ -655,7 +655,7 @@ class Element { // Mark textEl to update transform. // DON'T use markRedraw. It will cause Element itself to dirty again. - textEl.__dirty |= REDARAW_BIT; + textEl.__dirty |= REDRAW_BIT; if (textStyleChanged) { // Only mark style dirty if necessary. Update ZRText is costly. @@ -937,7 +937,7 @@ class Element { this._toggleHoverLayerFlag(false); // NOTE: avoid unexpected refresh when moving out from hover layer!! // Only clear from hover layer. - this.__dirty &= ~REDARAW_BIT; + this.__dirty &= ~REDRAW_BIT; } // Return used state. @@ -1024,7 +1024,7 @@ class Element { this._toggleHoverLayerFlag(false); // NOTE: avoid unexpected refresh when moving out from hover layer!! // Only clear from hover layer. - this.__dirty &= ~REDARAW_BIT; + this.__dirty &= ~REDRAW_BIT; } } } @@ -1354,7 +1354,7 @@ class Element { * Mark element needs to be repainted */ markRedraw() { - this.__dirty |= REDARAW_BIT; + this.__dirty |= REDRAW_BIT; const zr = this.__zr; if (zr) { if (this.__inHover) { @@ -1623,7 +1623,7 @@ class Element { elProto.dragging = false; elProto.ignoreClip = false; elProto.__inHover = false; - elProto.__dirty = REDARAW_BIT; + elProto.__dirty = REDRAW_BIT; const logs: Dictionary = {}; diff --git a/src/Storage.ts b/src/Storage.ts index 7c094f9fb..2abd1fcb8 100644 --- a/src/Storage.ts +++ b/src/Storage.ts @@ -8,7 +8,7 @@ import Element from './Element'; import timsort from './core/timsort'; import Displayable from './graphic/Displayable'; import Path from './graphic/Path'; -import { REDARAW_BIT } from './graphic/constants'; +import { REDRAW_BIT } from './graphic/constants'; let invalidZErrorLogged = false; function logInvalidZError() { @@ -141,7 +141,7 @@ export default class Storage { // Force to mark as dirty if group is dirty if (el.__dirty) { - child.__dirty |= REDARAW_BIT; + child.__dirty |= REDRAW_BIT; } this._updateAndAddDisplayable(child, clipPaths, includeIgnore); diff --git a/src/canvas/Layer.ts b/src/canvas/Layer.ts index 51876251c..2e76a71e1 100644 --- a/src/canvas/Layer.ts +++ b/src/canvas/Layer.ts @@ -10,7 +10,7 @@ import { getCanvasGradient } from './helper'; import { createCanvasPattern } from './graphic'; import Displayable from '../graphic/Displayable'; import BoundingRect from '../core/BoundingRect'; -import { REDARAW_BIT } from '../graphic/constants'; +import { REDRAW_BIT } from '../graphic/constants'; function returnFalse() { return false; @@ -281,7 +281,7 @@ export default class Layer extends Eventful { * or not painted this frame. */ const shouldPaint = el.shouldBePainted(viewWidth, viewHeight, true, true); - const prevRect = el.__isRendered && ((el.__dirty & REDARAW_BIT) || !shouldPaint) + const prevRect = el.__isRendered && ((el.__dirty & REDRAW_BIT) || !shouldPaint) ? el.getPrevPaintRect() : null; if (prevRect) { @@ -293,7 +293,7 @@ export default class Layer extends Eventful { * if the element should be brushed this frame and either being * dirty or not rendered before. */ - const curRect = shouldPaint && ((el.__dirty & REDARAW_BIT) || !el.__isRendered) + const curRect = shouldPaint && ((el.__dirty & REDRAW_BIT) || !el.__isRendered) ? el.getPaintRect() : null; if (curRect) { diff --git a/src/canvas/Painter.ts b/src/canvas/Painter.ts index f6c2fae08..5f69a4427 100644 --- a/src/canvas/Painter.ts +++ b/src/canvas/Painter.ts @@ -14,7 +14,7 @@ import { PainterBase } from '../PainterBase'; import BoundingRect from '../core/BoundingRect'; import IncrementalDisplayable from '../graphic/IncrementalDisplayable'; import Path from '../graphic/Path'; -import { REDARAW_BIT } from '../graphic/constants'; +import { REDRAW_BIT } from '../graphic/constants'; const HOVER_LAYER_ZLEVEL = 1e5; const CANVAS_ZLEVEL = 314159; @@ -751,7 +751,7 @@ export default class CanvasPainter implements PainterBase { updatePrevLayer(i); prevLayer = layer; } - if ((el.__dirty & REDARAW_BIT) && !el.__inHover) { // Ignore dirty elements in hover layer. + if ((el.__dirty & REDRAW_BIT) && !el.__inHover) { // Ignore dirty elements in hover layer. layer.__dirty = true; if (layer.incremental && layer.__drawIndex < 0) { // Start draw from the first dirty element. diff --git a/src/canvas/graphic.ts b/src/canvas/graphic.ts index b65f494f1..c775a461a 100644 --- a/src/canvas/graphic.ts +++ b/src/canvas/graphic.ts @@ -15,7 +15,7 @@ import { MatrixArray } from '../core/matrix'; import { map } from '../core/util'; import { normalizeLineDash } from '../graphic/helper/dashStyle'; import IncrementalDisplayable from '../graphic/IncrementalDisplayable'; -import { REDARAW_BIT, SHAPE_CHANGED_BIT } from '../graphic/constants'; +import { REDRAW_BIT, SHAPE_CHANGED_BIT } from '../graphic/constants'; const pathProxyForDraw = new PathProxy(true); @@ -648,7 +648,7 @@ export function brush( // Or this element will always been rendered in progressive rendering. // But other dirty bit should not be cleared, otherwise it cause the shape // can not be updated in this case. - el.__dirty &= ~REDARAW_BIT; + el.__dirty &= ~REDRAW_BIT; el.__isRendered = false; return; } diff --git a/src/core/event.ts b/src/core/event.ts index 0c4f8b0bf..c5fc28117 100644 --- a/src/core/event.ts +++ b/src/core/event.ts @@ -67,13 +67,16 @@ export function clientToLocal( // // BTW3, In ff, offsetX/offsetY is always 0. else if (env.browser.firefox + // use offsetX/offsetY for Firefox >= 39 + // PENDING: consider Firefox for Android and Firefox OS? >= 43 + && env.browser.version < '39' && (e as FirefoxMouseEvent).layerX != null && (e as FirefoxMouseEvent).layerX !== (e as MouseEvent).offsetX ) { out.zrX = (e as FirefoxMouseEvent).layerX; out.zrY = (e as FirefoxMouseEvent).layerY; } - // For IE6+, chrome, safari, opera. (When will ff support offsetX?) + // For IE6+, chrome, safari, opera, firefox >= 39 else if ((e as MouseEvent).offsetX != null) { out.zrX = (e as MouseEvent).offsetX; out.zrY = (e as MouseEvent).offsetY; diff --git a/src/core/util.ts b/src/core/util.ts index 7eae0db24..8b39f068a 100644 --- a/src/core/util.ts +++ b/src/core/util.ts @@ -1,3 +1,4 @@ +/* global: defineProperty */ import { Dictionary, ArrayLike, KeyOfDistributive } from './types'; import { GradientObject } from '../graphic/Gradient'; import { ImagePatternObject } from '../graphic/Pattern'; @@ -38,6 +39,7 @@ const nativeMap = arrayProto.map; // In case some env may redefine the global variable `Function`. const ctorFunction = function () {}.constructor; const protoFunction = ctorFunction ? ctorFunction.prototype : null; +const protoKey = '__proto__'; // Avoid assign to an exported constiable, for transforming to cjs. const methods: {[key: string]: Function} = {}; @@ -47,6 +49,7 @@ export function $override(name: string, fn: Function) { } let idStart = 0x0907; + /** * Generate unique id */ @@ -106,7 +109,8 @@ export function clone(source: T): T { else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) { result = {} as any; for (let key in source) { - if (source.hasOwnProperty(key)) { + // Check if key is __proto__ to avoid prototype pollution + if (source.hasOwnProperty(key) && key !== protoKey) { result[key] = clone(source[key]); } } @@ -131,7 +135,8 @@ export function merge(target: any, source: any, overwrite?: boolean): any { } for (let key in source) { - if (source.hasOwnProperty(key)) { + // Check if key is __proto__ to avoid prototype pollution + if (source.hasOwnProperty(key) && key !== protoKey) { const targetProp = target[key]; const sourceProp = source[key]; @@ -184,7 +189,8 @@ export function extend< } else { for (let key in source) { - if (source.hasOwnProperty(key)) { + // Check if key is __proto__ to avoid prototype pollution + if (source.hasOwnProperty(key) && key !== protoKey) { (target as S & T)[key] = (source as T & S)[key]; } } diff --git a/src/export.ts b/src/export.ts index 1b7dc35ed..7889e74a9 100644 --- a/src/export.ts +++ b/src/export.ts @@ -23,6 +23,7 @@ export { ElementProps } from './Element'; +export {default as Displayable, DisplayableProps} from './graphic/Displayable'; export {default as Group, GroupProps} from './graphic/Group'; export {default as Path, PathStyleProps, PathProps, PathStatePropNames, PathState} from './graphic/Path'; export {default as Image, ImageStyleProps, ImageProps, ImageState} from './graphic/Image'; diff --git a/src/graphic/Displayable.ts b/src/graphic/Displayable.ts index 5293d501f..20223e889 100644 --- a/src/graphic/Displayable.ts +++ b/src/graphic/Displayable.ts @@ -8,7 +8,7 @@ import { PropType, Dictionary, MapToType } from '../core/types'; import Path from './Path'; import { keys, extend, createObject } from '../core/util'; import Animator from '../animation/Animator'; -import { REDARAW_BIT, STYLE_CHANGED_BIT } from './constants'; +import { REDRAW_BIT, STYLE_CHANGED_BIT } from './constants'; // type CalculateTextPositionResult = ReturnType @@ -598,7 +598,7 @@ class Displayable extends Ele dispProto._rect = null; dispProto.dirtyRectTolerance = 0; - dispProto.__dirty = REDARAW_BIT | STYLE_CHANGED_BIT; + dispProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT; })() } diff --git a/src/graphic/Gradient.ts b/src/graphic/Gradient.ts index d05596090..6aafd7c3c 100644 --- a/src/graphic/Gradient.ts +++ b/src/graphic/Gradient.ts @@ -7,7 +7,7 @@ export interface GradientObject { colorStops: GradientColorStop[] - global: boolean + global?: boolean } export interface InnerGradientObject extends GradientObject { diff --git a/src/graphic/Path.ts b/src/graphic/Path.ts index 9776eface..f76da8de1 100644 --- a/src/graphic/Path.ts +++ b/src/graphic/Path.ts @@ -16,7 +16,7 @@ import { defaults, keys, extend, clone, isString, createObject } from '../core/u import Animator from '../animation/Animator'; import { lum } from '../tool/color'; import { DARK_LABEL_COLOR, LIGHT_LABEL_COLOR, DARK_MODE_THRESHOLD, LIGHTER_LABEL_COLOR } from '../config'; -import { REDARAW_BIT, SHAPE_CHANGED_BIT, STYLE_CHANGED_BIT } from './constants'; +import { REDRAW_BIT, SHAPE_CHANGED_BIT, STYLE_CHANGED_BIT } from './constants'; export interface PathStyleProps extends CommonStyleProps { @@ -193,7 +193,7 @@ class Path extends Displayable { (decalEl as any)[pathCopyParams[i]] = this[pathCopyParams[i]]; } - decalEl.__dirty |= REDARAW_BIT; + decalEl.__dirty |= REDRAW_BIT; } else if (this._decalEl) { this._decalEl = null; @@ -670,7 +670,7 @@ class Path extends Displayable { pathProto.segmentIgnoreThreshold = 0; pathProto.subPixelOptimize = false; pathProto.autoBatch = false; - pathProto.__dirty = REDARAW_BIT | STYLE_CHANGED_BIT | SHAPE_CHANGED_BIT; + pathProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT | SHAPE_CHANGED_BIT; })() } diff --git a/src/graphic/constants.ts b/src/graphic/constants.ts index f2cca43c3..70900bf98 100644 --- a/src/graphic/constants.ts +++ b/src/graphic/constants.ts @@ -1,4 +1,4 @@ // Bit masks to check which parts of element needs to be updated. -export const REDARAW_BIT = 1; +export const REDRAW_BIT = 1; export const STYLE_CHANGED_BIT = 2; export const SHAPE_CHANGED_BIT = 4; diff --git a/src/svg/graphic.ts b/src/svg/graphic.ts index 709b0a544..f7bbdfb22 100644 --- a/src/svg/graphic.ts +++ b/src/svg/graphic.ts @@ -87,7 +87,7 @@ function bindStyle(svgEl: SVGElement, style: AllStyleOption, el?: Path | TSpan | // only set opacity. stroke and fill cannot be applied to svg image if (el instanceof ZRImage) { - svgEl.style.opacity = opacity + ''; + attr(svgEl, 'opacity', opacity + ''); return; } @@ -137,7 +137,7 @@ function bindStyle(svgEl: SVGElement, style: AllStyleOption, el?: Path | TSpan | attr(svgEl, 'stroke-dashoffset', (lineDashOffset || 0) + ''); } else { - attr(svgEl, 'stroke-dasharray', ''); + attr(svgEl, 'stroke-dasharray', NONE); } // PENDING diff --git a/src/svg/helper/ShadowManager.ts b/src/svg/helper/ShadowManager.ts index 16814c0b6..f836444fa 100644 --- a/src/svg/helper/ShadowManager.ts +++ b/src/svg/helper/ShadowManager.ts @@ -73,7 +73,7 @@ export default class ShadowManager extends Definable { remove(svgElement: SVGElement, displayable: Displayable) { if ((displayable as DisplayableExtended)._shadowDom != null) { (displayable as DisplayableExtended)._shadowDom = null; - svgElement.style.filter = ''; + svgElement.removeAttribute('filter'); } } @@ -124,7 +124,7 @@ export default class ShadowManager extends Definable { (displayable as DisplayableExtended)._shadowDom = shadowDom; const id = shadowDom.getAttribute('id'); - svgElement.style.filter = 'url(#' + id + ')'; + svgElement.setAttribute('filter', 'url(#' + id + ')'); } removeUnused() { diff --git a/src/tool/color.ts b/src/tool/color.ts index 8638e7ddd..fb0cab500 100644 --- a/src/tool/color.ts +++ b/src/tool/color.ts @@ -440,6 +440,15 @@ type LerpFullOutput = { * @return Result color. If fullOutput, return {color: ..., leftIndex: ..., rightIndex: ..., value: ...}, */ +export function lerp( + normalizedValue: number, + colors: string[], + fullOutput: boolean +): LerpFullOutput +export function lerp( + normalizedValue: number, + colors: string[] +): string export function lerp( normalizedValue: number, colors: string[], diff --git a/src/tool/parseSVG.ts b/src/tool/parseSVG.ts index 7a071a2fb..7f52f19dc 100644 --- a/src/tool/parseSVG.ts +++ b/src/tool/parseSVG.ts @@ -479,7 +479,7 @@ class SVGParser { parseAttributes(xmlNode, img, this._defsUsePending, false, false); img.setStyle({ - image: xmlNode.getAttribute('xlink:href'), + image: xmlNode.getAttribute('xlink:href') || xmlNode.getAttribute('href'), x: +xmlNode.getAttribute('x'), y: +xmlNode.getAttribute('y'), width: +xmlNode.getAttribute('width'),