|   | 
| /* | 
| * 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. | 
| */ | 
|   | 
|   | 
| /** | 
|  * AUTO-GENERATED FILE. DO NOT MODIFY. | 
|  */ | 
|   | 
| /* | 
| * 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 WeakMap from 'zrender/lib/core/WeakMap.js'; | 
| import LRU from 'zrender/lib/core/LRU.js'; | 
| import { defaults, map, isArray, isString, isNumber } from 'zrender/lib/core/util.js'; | 
| import { getLeastCommonMultiple } from './number.js'; | 
| import { createSymbol } from './symbol.js'; | 
| import { brushSingle } from 'zrender/lib/canvas/graphic.js'; | 
| import { platformApi } from 'zrender/lib/core/platform.js'; | 
| var decalMap = new WeakMap(); | 
| var decalCache = new LRU(100); | 
| var decalKeys = ['symbol', 'symbolSize', 'symbolKeepAspect', 'color', 'backgroundColor', 'dashArrayX', 'dashArrayY', 'maxTileWidth', 'maxTileHeight']; | 
| /** | 
|  * Create or update pattern image from decal options | 
|  * | 
|  * @param {InnerDecalObject | 'none'} decalObject decal options, 'none' if no decal | 
|  * @return {Pattern} pattern with generated image, null if no decal | 
|  */ | 
|   | 
| export function createOrUpdatePatternFromDecal(decalObject, api) { | 
|   if (decalObject === 'none') { | 
|     return null; | 
|   } | 
|   | 
|   var dpr = api.getDevicePixelRatio(); | 
|   var zr = api.getZr(); | 
|   var isSVG = zr.painter.type === 'svg'; | 
|   | 
|   if (decalObject.dirty) { | 
|     decalMap["delete"](decalObject); | 
|   } | 
|   | 
|   var oldPattern = decalMap.get(decalObject); | 
|   | 
|   if (oldPattern) { | 
|     return oldPattern; | 
|   } | 
|   | 
|   var decalOpt = defaults(decalObject, { | 
|     symbol: 'rect', | 
|     symbolSize: 1, | 
|     symbolKeepAspect: true, | 
|     color: 'rgba(0, 0, 0, 0.2)', | 
|     backgroundColor: null, | 
|     dashArrayX: 5, | 
|     dashArrayY: 5, | 
|     rotation: 0, | 
|     maxTileWidth: 512, | 
|     maxTileHeight: 512 | 
|   }); | 
|   | 
|   if (decalOpt.backgroundColor === 'none') { | 
|     decalOpt.backgroundColor = null; | 
|   } | 
|   | 
|   var pattern = { | 
|     repeat: 'repeat' | 
|   }; | 
|   setPatternnSource(pattern); | 
|   pattern.rotation = decalOpt.rotation; | 
|   pattern.scaleX = pattern.scaleY = isSVG ? 1 : 1 / dpr; | 
|   decalMap.set(decalObject, pattern); | 
|   decalObject.dirty = false; | 
|   return pattern; | 
|   | 
|   function setPatternnSource(pattern) { | 
|     var keys = [dpr]; | 
|     var isValidKey = true; | 
|   | 
|     for (var i = 0; i < decalKeys.length; ++i) { | 
|       var value = decalOpt[decalKeys[i]]; | 
|   | 
|       if (value != null && !isArray(value) && !isString(value) && !isNumber(value) && typeof value !== 'boolean') { | 
|         isValidKey = false; | 
|         break; | 
|       } | 
|   | 
|       keys.push(value); | 
|     } | 
|   | 
|     var cacheKey; | 
|   | 
|     if (isValidKey) { | 
|       cacheKey = keys.join(',') + (isSVG ? '-svg' : ''); | 
|       var cache = decalCache.get(cacheKey); | 
|   | 
|       if (cache) { | 
|         isSVG ? pattern.svgElement = cache : pattern.image = cache; | 
|       } | 
|     } | 
|   | 
|     var dashArrayX = normalizeDashArrayX(decalOpt.dashArrayX); | 
|     var dashArrayY = normalizeDashArrayY(decalOpt.dashArrayY); | 
|     var symbolArray = normalizeSymbolArray(decalOpt.symbol); | 
|     var lineBlockLengthsX = getLineBlockLengthX(dashArrayX); | 
|     var lineBlockLengthY = getLineBlockLengthY(dashArrayY); | 
|     var canvas = !isSVG && platformApi.createCanvas(); | 
|     var svgRoot = isSVG && { | 
|       tag: 'g', | 
|       attrs: {}, | 
|       key: 'dcl', | 
|       children: [] | 
|     }; | 
|     var pSize = getPatternSize(); | 
|     var ctx; | 
|   | 
|     if (canvas) { | 
|       canvas.width = pSize.width * dpr; | 
|       canvas.height = pSize.height * dpr; | 
|       ctx = canvas.getContext('2d'); | 
|     } | 
|   | 
|     brushDecal(); | 
|   | 
|     if (isValidKey) { | 
|       decalCache.put(cacheKey, canvas || svgRoot); | 
|     } | 
|   | 
|     pattern.image = canvas; | 
|     pattern.svgElement = svgRoot; | 
|     pattern.svgWidth = pSize.width; | 
|     pattern.svgHeight = pSize.height; | 
|     /** | 
|      * Get minumum length that can make a repeatable pattern. | 
|      * | 
|      * @return {Object} pattern width and height | 
|      */ | 
|   | 
|     function getPatternSize() { | 
|       /** | 
|        * For example, if dash is [[3, 2], [2, 1]] for X, it looks like | 
|        * |---  ---  ---  ---  --- ... | 
|        * |-- -- -- -- -- -- -- -- ... | 
|        * |---  ---  ---  ---  --- ... | 
|        * |-- -- -- -- -- -- -- -- ... | 
|        * So the minumum length of X is 15, | 
|        * which is the least common multiple of `3 + 2` and `2 + 1` | 
|        * |---  ---  ---  |---  --- ... | 
|        * |-- -- -- -- -- |-- -- -- ... | 
|        */ | 
|       var width = 1; | 
|   | 
|       for (var i = 0, xlen = lineBlockLengthsX.length; i < xlen; ++i) { | 
|         width = getLeastCommonMultiple(width, lineBlockLengthsX[i]); | 
|       } | 
|   | 
|       var symbolRepeats = 1; | 
|   | 
|       for (var i = 0, xlen = symbolArray.length; i < xlen; ++i) { | 
|         symbolRepeats = getLeastCommonMultiple(symbolRepeats, symbolArray[i].length); | 
|       } | 
|   | 
|       width *= symbolRepeats; | 
|       var height = lineBlockLengthY * lineBlockLengthsX.length * symbolArray.length; | 
|   | 
|       if (process.env.NODE_ENV !== 'production') { | 
|         var warn = function (attrName) { | 
|           /* eslint-disable-next-line */ | 
|           console.warn("Calculated decal size is greater than " + attrName + " due to decal option settings so " + attrName + " is used for the decal size. Please consider changing the decal option to make a smaller decal or set " + attrName + " to be larger to avoid incontinuity."); | 
|         }; | 
|   | 
|         if (width > decalOpt.maxTileWidth) { | 
|           warn('maxTileWidth'); | 
|         } | 
|   | 
|         if (height > decalOpt.maxTileHeight) { | 
|           warn('maxTileHeight'); | 
|         } | 
|       } | 
|   | 
|       return { | 
|         width: Math.max(1, Math.min(width, decalOpt.maxTileWidth)), | 
|         height: Math.max(1, Math.min(height, decalOpt.maxTileHeight)) | 
|       }; | 
|     } | 
|   | 
|     function brushDecal() { | 
|       if (ctx) { | 
|         ctx.clearRect(0, 0, canvas.width, canvas.height); | 
|   | 
|         if (decalOpt.backgroundColor) { | 
|           ctx.fillStyle = decalOpt.backgroundColor; | 
|           ctx.fillRect(0, 0, canvas.width, canvas.height); | 
|         } | 
|       } | 
|   | 
|       var ySum = 0; | 
|   | 
|       for (var i = 0; i < dashArrayY.length; ++i) { | 
|         ySum += dashArrayY[i]; | 
|       } | 
|   | 
|       if (ySum <= 0) { | 
|         // dashArrayY is 0, draw nothing | 
|         return; | 
|       } | 
|   | 
|       var y = -lineBlockLengthY; | 
|       var yId = 0; | 
|       var yIdTotal = 0; | 
|       var xId0 = 0; | 
|   | 
|       while (y < pSize.height) { | 
|         if (yId % 2 === 0) { | 
|           var symbolYId = yIdTotal / 2 % symbolArray.length; | 
|           var x = 0; | 
|           var xId1 = 0; | 
|           var xId1Total = 0; | 
|   | 
|           while (x < pSize.width * 2) { | 
|             var xSum = 0; | 
|   | 
|             for (var i = 0; i < dashArrayX[xId0].length; ++i) { | 
|               xSum += dashArrayX[xId0][i]; | 
|             } | 
|   | 
|             if (xSum <= 0) { | 
|               // Skip empty line | 
|               break; | 
|             } // E.g., [15, 5, 20, 5] draws only for 15 and 20 | 
|   | 
|   | 
|             if (xId1 % 2 === 0) { | 
|               var size = (1 - decalOpt.symbolSize) * 0.5; | 
|               var left = x + dashArrayX[xId0][xId1] * size; | 
|               var top_1 = y + dashArrayY[yId] * size; | 
|               var width = dashArrayX[xId0][xId1] * decalOpt.symbolSize; | 
|               var height = dashArrayY[yId] * decalOpt.symbolSize; | 
|               var symbolXId = xId1Total / 2 % symbolArray[symbolYId].length; | 
|               brushSymbol(left, top_1, width, height, symbolArray[symbolYId][symbolXId]); | 
|             } | 
|   | 
|             x += dashArrayX[xId0][xId1]; | 
|             ++xId1Total; | 
|             ++xId1; | 
|   | 
|             if (xId1 === dashArrayX[xId0].length) { | 
|               xId1 = 0; | 
|             } | 
|           } | 
|   | 
|           ++xId0; | 
|   | 
|           if (xId0 === dashArrayX.length) { | 
|             xId0 = 0; | 
|           } | 
|         } | 
|   | 
|         y += dashArrayY[yId]; | 
|         ++yIdTotal; | 
|         ++yId; | 
|   | 
|         if (yId === dashArrayY.length) { | 
|           yId = 0; | 
|         } | 
|       } | 
|   | 
|       function brushSymbol(x, y, width, height, symbolType) { | 
|         var scale = isSVG ? 1 : dpr; | 
|         var symbol = createSymbol(symbolType, x * scale, y * scale, width * scale, height * scale, decalOpt.color, decalOpt.symbolKeepAspect); | 
|   | 
|         if (isSVG) { | 
|           var symbolVNode = zr.painter.renderOneToVNode(symbol); | 
|   | 
|           if (symbolVNode) { | 
|             svgRoot.children.push(symbolVNode); | 
|           } | 
|         } else { | 
|           // Paint to canvas for all other renderers. | 
|           brushSingle(ctx, symbol); | 
|         } | 
|       } | 
|     } | 
|   } | 
| } | 
| /** | 
|  * Convert symbol array into normalized array | 
|  * | 
|  * @param {string | (string | string[])[]} symbol symbol input | 
|  * @return {string[][]} normolized symbol array | 
|  */ | 
|   | 
| function normalizeSymbolArray(symbol) { | 
|   if (!symbol || symbol.length === 0) { | 
|     return [['rect']]; | 
|   } | 
|   | 
|   if (isString(symbol)) { | 
|     return [[symbol]]; | 
|   } | 
|   | 
|   var isAllString = true; | 
|   | 
|   for (var i = 0; i < symbol.length; ++i) { | 
|     if (!isString(symbol[i])) { | 
|       isAllString = false; | 
|       break; | 
|     } | 
|   } | 
|   | 
|   if (isAllString) { | 
|     return normalizeSymbolArray([symbol]); | 
|   } | 
|   | 
|   var result = []; | 
|   | 
|   for (var i = 0; i < symbol.length; ++i) { | 
|     if (isString(symbol[i])) { | 
|       result.push([symbol[i]]); | 
|     } else { | 
|       result.push(symbol[i]); | 
|     } | 
|   } | 
|   | 
|   return result; | 
| } | 
| /** | 
|  * Convert dash input into dashArray | 
|  * | 
|  * @param {DecalDashArrayX} dash dash input | 
|  * @return {number[][]} normolized dash array | 
|  */ | 
|   | 
|   | 
| function normalizeDashArrayX(dash) { | 
|   if (!dash || dash.length === 0) { | 
|     return [[0, 0]]; | 
|   } | 
|   | 
|   if (isNumber(dash)) { | 
|     var dashValue = Math.ceil(dash); | 
|     return [[dashValue, dashValue]]; | 
|   } | 
|   /** | 
|    * [20, 5] should be normalized into [[20, 5]], | 
|    * while [20, [5, 10]] should be normalized into [[20, 20], [5, 10]] | 
|    */ | 
|   | 
|   | 
|   var isAllNumber = true; | 
|   | 
|   for (var i = 0; i < dash.length; ++i) { | 
|     if (!isNumber(dash[i])) { | 
|       isAllNumber = false; | 
|       break; | 
|     } | 
|   } | 
|   | 
|   if (isAllNumber) { | 
|     return normalizeDashArrayX([dash]); | 
|   } | 
|   | 
|   var result = []; | 
|   | 
|   for (var i = 0; i < dash.length; ++i) { | 
|     if (isNumber(dash[i])) { | 
|       var dashValue = Math.ceil(dash[i]); | 
|       result.push([dashValue, dashValue]); | 
|     } else { | 
|       var dashValue = map(dash[i], function (n) { | 
|         return Math.ceil(n); | 
|       }); | 
|   | 
|       if (dashValue.length % 2 === 1) { | 
|         // [4, 2, 1] means |----  -    -- |----  -    -- | | 
|         // so normalize it to be [4, 2, 1, 4, 2, 1] | 
|         result.push(dashValue.concat(dashValue)); | 
|       } else { | 
|         result.push(dashValue); | 
|       } | 
|     } | 
|   } | 
|   | 
|   return result; | 
| } | 
| /** | 
|  * Convert dash input into dashArray | 
|  * | 
|  * @param {DecalDashArrayY} dash dash input | 
|  * @return {number[]} normolized dash array | 
|  */ | 
|   | 
|   | 
| function normalizeDashArrayY(dash) { | 
|   if (!dash || typeof dash === 'object' && dash.length === 0) { | 
|     return [0, 0]; | 
|   } | 
|   | 
|   if (isNumber(dash)) { | 
|     var dashValue_1 = Math.ceil(dash); | 
|     return [dashValue_1, dashValue_1]; | 
|   } | 
|   | 
|   var dashValue = map(dash, function (n) { | 
|     return Math.ceil(n); | 
|   }); | 
|   return dash.length % 2 ? dashValue.concat(dashValue) : dashValue; | 
| } | 
| /** | 
|  * Get block length of each line. A block is the length of dash line and space. | 
|  * For example, a line with [4, 1] has a dash line of 4 and a space of 1 after | 
|  * that, so the block length of this line is 5. | 
|  * | 
|  * @param {number[][]} dash dash arrary of X or Y | 
|  * @return {number[]} block length of each line | 
|  */ | 
|   | 
|   | 
| function getLineBlockLengthX(dash) { | 
|   return map(dash, function (line) { | 
|     return getLineBlockLengthY(line); | 
|   }); | 
| } | 
|   | 
| function getLineBlockLengthY(dash) { | 
|   var blockLength = 0; | 
|   | 
|   for (var i = 0; i < dash.length; ++i) { | 
|     blockLength += dash[i]; | 
|   } | 
|   | 
|   if (dash.length % 2 === 1) { | 
|     // [4, 2, 1] means |----  -    -- |----  -    -- | | 
|     // So total length is (4 + 2 + 1) * 2 | 
|     return blockLength * 2; | 
|   } | 
|   | 
|   return blockLength; | 
| } |