layout.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. // Layout helpers for each component positioning
  41. import * as zrUtil from 'zrender/lib/core/util.js';
  42. import BoundingRect from 'zrender/lib/core/BoundingRect.js';
  43. import { parsePercent } from './number.js';
  44. import * as formatUtil from './format.js';
  45. import { error } from './log.js';
  46. import { BoxCoordinateSystemCoordFrom, getCoordForBoxCoordSys } from '../core/CoordinateSystem.js';
  47. var each = zrUtil.each;
  48. /**
  49. * @public
  50. */
  51. export var LOCATION_PARAMS = ['left', 'right', 'top', 'bottom', 'width', 'height'];
  52. /**
  53. * @public
  54. */
  55. export var HV_NAMES = [['width', 'left', 'right'], ['height', 'top', 'bottom']];
  56. function boxLayout(orient, group, gap, maxWidth, maxHeight) {
  57. var x = 0;
  58. var y = 0;
  59. if (maxWidth == null) {
  60. maxWidth = Infinity;
  61. }
  62. if (maxHeight == null) {
  63. maxHeight = Infinity;
  64. }
  65. var currentLineMaxSize = 0;
  66. group.eachChild(function (child, idx) {
  67. var rect = child.getBoundingRect();
  68. var nextChild = group.childAt(idx + 1);
  69. var nextChildRect = nextChild && nextChild.getBoundingRect();
  70. var nextX;
  71. var nextY;
  72. if (orient === 'horizontal') {
  73. var moveX = rect.width + (nextChildRect ? -nextChildRect.x + rect.x : 0);
  74. nextX = x + moveX;
  75. // Wrap when width exceeds maxWidth or meet a `newline` group
  76. // FIXME compare before adding gap?
  77. if (nextX > maxWidth || child.newline) {
  78. x = 0;
  79. nextX = moveX;
  80. y += currentLineMaxSize + gap;
  81. currentLineMaxSize = rect.height;
  82. } else {
  83. // FIXME: consider rect.y is not `0`?
  84. currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);
  85. }
  86. } else {
  87. var moveY = rect.height + (nextChildRect ? -nextChildRect.y + rect.y : 0);
  88. nextY = y + moveY;
  89. // Wrap when width exceeds maxHeight or meet a `newline` group
  90. if (nextY > maxHeight || child.newline) {
  91. x += currentLineMaxSize + gap;
  92. y = 0;
  93. nextY = moveY;
  94. currentLineMaxSize = rect.width;
  95. } else {
  96. currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);
  97. }
  98. }
  99. if (child.newline) {
  100. return;
  101. }
  102. child.x = x;
  103. child.y = y;
  104. child.markRedraw();
  105. orient === 'horizontal' ? x = nextX + gap : y = nextY + gap;
  106. });
  107. }
  108. /**
  109. * VBox or HBox layouting
  110. * @param {string} orient
  111. * @param {module:zrender/graphic/Group} group
  112. * @param {number} gap
  113. * @param {number} [width=Infinity]
  114. * @param {number} [height=Infinity]
  115. */
  116. export var box = boxLayout;
  117. /**
  118. * VBox layouting
  119. * @param {module:zrender/graphic/Group} group
  120. * @param {number} gap
  121. * @param {number} [width=Infinity]
  122. * @param {number} [height=Infinity]
  123. */
  124. export var vbox = zrUtil.curry(boxLayout, 'vertical');
  125. /**
  126. * HBox layouting
  127. * @param {module:zrender/graphic/Group} group
  128. * @param {number} gap
  129. * @param {number} [width=Infinity]
  130. * @param {number} [height=Infinity]
  131. */
  132. export var hbox = zrUtil.curry(boxLayout, 'horizontal');
  133. export function getBoxLayoutParams(boxLayoutModel, ignoreParent) {
  134. return {
  135. left: boxLayoutModel.getShallow('left', ignoreParent),
  136. top: boxLayoutModel.getShallow('top', ignoreParent),
  137. right: boxLayoutModel.getShallow('right', ignoreParent),
  138. bottom: boxLayoutModel.getShallow('bottom', ignoreParent),
  139. width: boxLayoutModel.getShallow('width', ignoreParent),
  140. height: boxLayoutModel.getShallow('height', ignoreParent)
  141. };
  142. }
  143. function getViewRectAndCenterForCircleLayout(seriesModel, api) {
  144. var layoutRef = createBoxLayoutReference(seriesModel, api, {
  145. enableLayoutOnlyByCenter: true
  146. });
  147. var boxLayoutParams = seriesModel.getBoxLayoutParams();
  148. var viewRect;
  149. var center;
  150. if (layoutRef.type === BoxLayoutReferenceType.point) {
  151. center = layoutRef.refPoint;
  152. // `viewRect` is required in `pie/labelLayout.ts`.
  153. viewRect = getLayoutRect(boxLayoutParams, {
  154. width: api.getWidth(),
  155. height: api.getHeight()
  156. });
  157. } else {
  158. // layoutRef.type === layout.BoxLayoutReferenceType.rect
  159. var centerOption = seriesModel.get('center');
  160. var centerOptionArr = zrUtil.isArray(centerOption) ? centerOption : [centerOption, centerOption];
  161. viewRect = getLayoutRect(boxLayoutParams, layoutRef.refContainer);
  162. center = layoutRef.boxCoordFrom === BoxCoordinateSystemCoordFrom.coord2 ? layoutRef.refPoint // option `series.center` has been used as coord.
  163. : [parsePercent(centerOptionArr[0], viewRect.width) + viewRect.x, parsePercent(centerOptionArr[1], viewRect.height) + viewRect.y];
  164. }
  165. return {
  166. viewRect: viewRect,
  167. center: center
  168. };
  169. }
  170. export function getCircleLayout(seriesModel, api) {
  171. // center can be string or number when coordinateSystem is specified
  172. var _a = getViewRectAndCenterForCircleLayout(seriesModel, api),
  173. viewRect = _a.viewRect,
  174. center = _a.center;
  175. var radius = seriesModel.get('radius');
  176. if (!zrUtil.isArray(radius)) {
  177. radius = [0, radius];
  178. }
  179. var width = parsePercent(viewRect.width, api.getWidth());
  180. var height = parsePercent(viewRect.height, api.getHeight());
  181. var size = Math.min(width, height);
  182. var r0 = parsePercent(radius[0], size / 2);
  183. var r = parsePercent(radius[1], size / 2);
  184. return {
  185. cx: center[0],
  186. cy: center[1],
  187. r0: r0,
  188. r: r,
  189. viewRect: viewRect
  190. };
  191. }
  192. /**
  193. * Parse position info.
  194. */
  195. export function getLayoutRect(positionInfo, containerRect,
  196. // This is the space from the `containerRect` to the returned bounding rect.
  197. // Commonly used in option `legend.padding`, `timeline.padding`, `title.padding`,
  198. // `visualMap.padding`, ...
  199. // [NOTICE]:
  200. // It's named `margin`, because it's the space that outside the bounding rect. But from
  201. // the perspective of the the caller, it's commonly used as the `padding` of a component,
  202. // because conventionally background color covers this space.
  203. // [BEHAVIOR]:
  204. // - If width/height is specified, `margin` does not effect them.
  205. // - Otherwise, they are calculated based on the rect that `containerRect` shrinked by `margin`.
  206. // - left/right/top/bottom are based on the rect that `containerRect` shrinked by `margin`.
  207. margin) {
  208. margin = formatUtil.normalizeCssArray(margin || 0);
  209. var containerWidth = containerRect.width;
  210. var containerHeight = containerRect.height;
  211. var left = parsePercent(positionInfo.left, containerWidth);
  212. var top = parsePercent(positionInfo.top, containerHeight);
  213. var right = parsePercent(positionInfo.right, containerWidth);
  214. var bottom = parsePercent(positionInfo.bottom, containerHeight);
  215. var width = parsePercent(positionInfo.width, containerWidth);
  216. var height = parsePercent(positionInfo.height, containerHeight);
  217. var verticalMargin = margin[2] + margin[0];
  218. var horizontalMargin = margin[1] + margin[3];
  219. var aspect = positionInfo.aspect;
  220. // If width is not specified, calculate width from left and right
  221. if (isNaN(width)) {
  222. width = containerWidth - right - horizontalMargin - left;
  223. }
  224. if (isNaN(height)) {
  225. height = containerHeight - bottom - verticalMargin - top;
  226. }
  227. if (aspect != null) {
  228. // If width and height are not given
  229. // 1. Graph should not exceeds the container
  230. // 2. Aspect must be keeped
  231. // 3. Graph should take the space as more as possible
  232. // FIXME
  233. // Margin is not considered, because there is no case that both
  234. // using margin and aspect so far.
  235. if (isNaN(width) && isNaN(height)) {
  236. // PENDING: if only `left` or `right` is defined, perhaps it's more preferable to
  237. // calculate size based on `containerWidth - left` or `containerWidth - left` here,
  238. // but for backward compatibility we do not change it.
  239. if (aspect > containerWidth / containerHeight) {
  240. width = containerWidth * 0.8;
  241. } else {
  242. height = containerHeight * 0.8;
  243. }
  244. }
  245. // Calculate width or height with given aspect
  246. if (isNaN(width)) {
  247. width = aspect * height;
  248. }
  249. if (isNaN(height)) {
  250. height = width / aspect;
  251. }
  252. }
  253. // If left is not specified, calculate left from right and width
  254. if (isNaN(left)) {
  255. left = containerWidth - right - width - horizontalMargin;
  256. }
  257. if (isNaN(top)) {
  258. top = containerHeight - bottom - height - verticalMargin;
  259. }
  260. // Align left and top
  261. switch (positionInfo.left || positionInfo.right) {
  262. case 'center':
  263. left = containerWidth / 2 - width / 2 - margin[3];
  264. break;
  265. case 'right':
  266. left = containerWidth - width - horizontalMargin;
  267. break;
  268. }
  269. switch (positionInfo.top || positionInfo.bottom) {
  270. case 'middle':
  271. case 'center':
  272. top = containerHeight / 2 - height / 2 - margin[0];
  273. break;
  274. case 'bottom':
  275. top = containerHeight - height - verticalMargin;
  276. break;
  277. }
  278. // If something is wrong and left, top, width, height are calculated as NaN
  279. left = left || 0;
  280. top = top || 0;
  281. if (isNaN(width)) {
  282. // Width may be NaN if only one value is given except width
  283. width = containerWidth - horizontalMargin - left - (right || 0);
  284. }
  285. if (isNaN(height)) {
  286. // Height may be NaN if only one value is given except height
  287. height = containerHeight - verticalMargin - top - (bottom || 0);
  288. }
  289. var rect = new BoundingRect((containerRect.x || 0) + left + margin[3], (containerRect.y || 0) + top + margin[0], width, height);
  290. rect.margin = margin;
  291. return rect;
  292. }
  293. /**
  294. * PENDING:
  295. * when preserveAspect: 'cover' and aspect is near Infinity
  296. * or when preserveAspect: 'contain' and aspect is near 0,
  297. * the result width or height is near Inifity. It's logically correct,
  298. * Therefore currently we do not handle it, until bad cases arise.
  299. */
  300. export function applyPreserveAspect(component, layoutRect,
  301. // That is, `width / height`.
  302. // Assume `aspect` is positive.
  303. aspect) {
  304. var preserveAspect = component.getShallow('preserveAspect', true);
  305. if (!preserveAspect) {
  306. return layoutRect;
  307. }
  308. var actualAspect = layoutRect.width / layoutRect.height;
  309. if (Math.abs(Math.atan(aspect) - Math.atan(actualAspect)) < 1e-9) {
  310. return layoutRect;
  311. }
  312. var preserveAspectAlign = component.getShallow('preserveAspectAlign', true);
  313. var preserveAspectVerticalAlign = component.getShallow('preserveAspectVerticalAlign', true);
  314. var layoutOptInner = {
  315. width: layoutRect.width,
  316. height: layoutRect.height
  317. };
  318. var isCover = preserveAspect === 'cover';
  319. if (actualAspect > aspect && !isCover || actualAspect < aspect && isCover) {
  320. layoutOptInner.width = layoutRect.height * aspect;
  321. preserveAspectAlign === 'left' ? layoutOptInner.left = 0 : preserveAspectAlign === 'right' ? layoutOptInner.right = 0 : layoutOptInner.left = 'center';
  322. } else {
  323. layoutOptInner.height = layoutRect.width / aspect;
  324. preserveAspectVerticalAlign === 'top' ? layoutOptInner.top = 0 : preserveAspectVerticalAlign === 'bottom' ? layoutOptInner.bottom = 0 : layoutOptInner.top = 'middle';
  325. }
  326. return getLayoutRect(layoutOptInner, layoutRect);
  327. }
  328. export var BoxLayoutReferenceType = {
  329. rect: 1,
  330. point: 2
  331. };
  332. /**
  333. * Uniformly calculate layout reference (rect or center) based on either:
  334. * - viewport:
  335. * - Get `refContainer` as `{x: 0, y: 0, width: api.getWidth(), height: api.getHeight()}`
  336. * - coordinate system, which can serve in several ways:
  337. * - Use `dataToPoint` to get the `refPoint`, such as, in cartesian2d coord sys.
  338. * - Use `dataToLayout` to get the `refContainer`, such as, in matrix coord sys.
  339. */
  340. export function createBoxLayoutReference(model, api, opt) {
  341. var refContainer;
  342. var refPoint;
  343. var layoutRefType;
  344. var boxCoordSys = model.boxCoordinateSystem;
  345. var boxCoordFrom;
  346. if (boxCoordSys) {
  347. var _a = getCoordForBoxCoordSys(model),
  348. coord = _a.coord,
  349. from = _a.from;
  350. // Do not use `clamp` in `dataToLayout` and `dataToPoint`, because:
  351. // 1. Should support overflow (such as, by dataZoom), where NaN should be in the result.
  352. // 2. Be consistent with the way used in `series.data`
  353. if (boxCoordSys.dataToLayout) {
  354. layoutRefType = BoxLayoutReferenceType.rect;
  355. boxCoordFrom = from;
  356. var result = boxCoordSys.dataToLayout(coord);
  357. refContainer = result.contentRect || result.rect;
  358. } else if (opt && opt.enableLayoutOnlyByCenter && boxCoordSys.dataToPoint) {
  359. layoutRefType = BoxLayoutReferenceType.point;
  360. boxCoordFrom = from;
  361. refPoint = boxCoordSys.dataToPoint(coord);
  362. } else {
  363. if (process.env.NODE_ENV !== 'production') {
  364. error(model.type + "[" + model.componentIndex + "]" + (" layout based on " + boxCoordSys.type + " is not supported."));
  365. }
  366. }
  367. }
  368. if (layoutRefType == null) {
  369. layoutRefType = BoxLayoutReferenceType.rect;
  370. }
  371. if (layoutRefType === BoxLayoutReferenceType.rect) {
  372. if (!refContainer) {
  373. refContainer = {
  374. x: 0,
  375. y: 0,
  376. width: api.getWidth(),
  377. height: api.getHeight()
  378. };
  379. }
  380. refPoint = [refContainer.x + refContainer.width / 2, refContainer.y + refContainer.height / 2];
  381. }
  382. return {
  383. type: layoutRefType,
  384. refContainer: refContainer,
  385. refPoint: refPoint,
  386. boxCoordFrom: boxCoordFrom
  387. };
  388. }
  389. /**
  390. * Position a zr element in viewport
  391. * Group position is specified by either
  392. * {left, top}, {right, bottom}
  393. * If all properties exists, right and bottom will be igonred.
  394. *
  395. * Logic:
  396. * 1. Scale (against origin point in parent coord)
  397. * 2. Rotate (against origin point in parent coord)
  398. * 3. Translate (with el.position by this method)
  399. * So this method only fixes the last step 'Translate', which does not affect
  400. * scaling and rotating.
  401. *
  402. * If be called repeatedly with the same input el, the same result will be gotten.
  403. *
  404. * Return true if the layout happened.
  405. *
  406. * @param el Should have `getBoundingRect` method.
  407. * @param positionInfo
  408. * @param positionInfo.left
  409. * @param positionInfo.top
  410. * @param positionInfo.right
  411. * @param positionInfo.bottom
  412. * @param positionInfo.width Only for opt.boundingModel: 'raw'
  413. * @param positionInfo.height Only for opt.boundingModel: 'raw'
  414. * @param containerRect
  415. * @param margin
  416. * @param opt
  417. * @param opt.hv Only horizontal or only vertical. Default to be [1, 1]
  418. * @param opt.boundingMode
  419. * Specify how to calculate boundingRect when locating.
  420. * 'all': Position the boundingRect that is transformed and uioned
  421. * both itself and its descendants.
  422. * This mode simplies confine the elements in the bounding
  423. * of their container (e.g., using 'right: 0').
  424. * 'raw': Position the boundingRect that is not transformed and only itself.
  425. * This mode is useful when you want a element can overflow its
  426. * container. (Consider a rotated circle needs to be located in a corner.)
  427. * In this mode positionInfo.width/height can only be number.
  428. */
  429. export function positionElement(el, positionInfo, containerRect, margin, opt, out) {
  430. var h = !opt || !opt.hv || opt.hv[0];
  431. var v = !opt || !opt.hv || opt.hv[1];
  432. var boundingMode = opt && opt.boundingMode || 'all';
  433. out = out || el;
  434. out.x = el.x;
  435. out.y = el.y;
  436. if (!h && !v) {
  437. return false;
  438. }
  439. var rect;
  440. if (boundingMode === 'raw') {
  441. rect = el.type === 'group' ? new BoundingRect(0, 0, +positionInfo.width || 0, +positionInfo.height || 0) : el.getBoundingRect();
  442. } else {
  443. rect = el.getBoundingRect();
  444. if (el.needLocalTransform()) {
  445. var transform = el.getLocalTransform();
  446. // Notice: raw rect may be inner object of el,
  447. // which should not be modified.
  448. rect = rect.clone();
  449. rect.applyTransform(transform);
  450. }
  451. }
  452. // The real width and height can not be specified but calculated by the given el.
  453. var layoutRect = getLayoutRect(zrUtil.defaults({
  454. width: rect.width,
  455. height: rect.height
  456. }, positionInfo), containerRect, margin);
  457. // Because 'tranlate' is the last step in transform
  458. // (see zrender/core/Transformable#getLocalTransform),
  459. // we can just only modify el.position to get final result.
  460. var dx = h ? layoutRect.x - rect.x : 0;
  461. var dy = v ? layoutRect.y - rect.y : 0;
  462. if (boundingMode === 'raw') {
  463. out.x = dx;
  464. out.y = dy;
  465. } else {
  466. out.x += dx;
  467. out.y += dy;
  468. }
  469. if (out === el) {
  470. el.markRedraw();
  471. }
  472. return true;
  473. }
  474. /**
  475. * @param option Contains some of the properties in HV_NAMES.
  476. * @param hvIdx 0: horizontal; 1: vertical.
  477. */
  478. export function sizeCalculable(option, hvIdx) {
  479. return option[HV_NAMES[hvIdx][0]] != null || option[HV_NAMES[hvIdx][1]] != null && option[HV_NAMES[hvIdx][2]] != null;
  480. }
  481. export function fetchLayoutMode(ins) {
  482. var layoutMode = ins.layoutMode || ins.constructor.layoutMode;
  483. return zrUtil.isObject(layoutMode) ? layoutMode : layoutMode ? {
  484. type: layoutMode
  485. } : null;
  486. }
  487. /**
  488. * Consider Case:
  489. * When default option has {left: 0, width: 100}, and we set {right: 0}
  490. * through setOption or media query, using normal zrUtil.merge will cause
  491. * {right: 0} does not take effect.
  492. *
  493. * @example
  494. * ComponentModel.extend({
  495. * init: function () {
  496. * ...
  497. * let inputPositionParams = layout.getLayoutParams(option);
  498. * this.mergeOption(inputPositionParams);
  499. * },
  500. * mergeOption: function (newOption) {
  501. * newOption && zrUtil.merge(thisOption, newOption, true);
  502. * layout.mergeLayoutParam(thisOption, newOption);
  503. * }
  504. * });
  505. *
  506. * @param targetOption
  507. * @param newOption
  508. * @param opt
  509. */
  510. export function mergeLayoutParam(targetOption, newOption, opt) {
  511. var ignoreSize = opt && opt.ignoreSize;
  512. !zrUtil.isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);
  513. var hResult = merge(HV_NAMES[0], 0);
  514. var vResult = merge(HV_NAMES[1], 1);
  515. copy(HV_NAMES[0], targetOption, hResult);
  516. copy(HV_NAMES[1], targetOption, vResult);
  517. function merge(names, hvIdx) {
  518. var newParams = {};
  519. var newValueCount = 0;
  520. var merged = {};
  521. var mergedValueCount = 0;
  522. var enoughParamNumber = 2;
  523. each(names, function (name) {
  524. merged[name] = targetOption[name];
  525. });
  526. each(names, function (name) {
  527. // Consider case: newOption.width is null, which is
  528. // set by user for removing width setting.
  529. zrUtil.hasOwn(newOption, name) && (newParams[name] = merged[name] = newOption[name]);
  530. hasValue(newParams, name) && newValueCount++;
  531. hasValue(merged, name) && mergedValueCount++;
  532. });
  533. if (ignoreSize[hvIdx]) {
  534. // Only one of left/right is premitted to exist.
  535. if (hasValue(newOption, names[1])) {
  536. merged[names[2]] = null;
  537. } else if (hasValue(newOption, names[2])) {
  538. merged[names[1]] = null;
  539. }
  540. return merged;
  541. }
  542. // Case: newOption: {width: ..., right: ...},
  543. // or targetOption: {right: ...} and newOption: {width: ...},
  544. // There is no conflict when merged only has params count
  545. // little than enoughParamNumber.
  546. if (mergedValueCount === enoughParamNumber || !newValueCount) {
  547. return merged;
  548. }
  549. // Case: newOption: {width: ..., right: ...},
  550. // Than we can make sure user only want those two, and ignore
  551. // all origin params in targetOption.
  552. else if (newValueCount >= enoughParamNumber) {
  553. return newParams;
  554. } else {
  555. // Chose another param from targetOption by priority.
  556. for (var i = 0; i < names.length; i++) {
  557. var name_1 = names[i];
  558. if (!zrUtil.hasOwn(newParams, name_1) && zrUtil.hasOwn(targetOption, name_1)) {
  559. newParams[name_1] = targetOption[name_1];
  560. break;
  561. }
  562. }
  563. return newParams;
  564. }
  565. }
  566. function hasValue(obj, name) {
  567. return obj[name] != null && obj[name] !== 'auto';
  568. }
  569. function copy(names, target, source) {
  570. each(names, function (name) {
  571. target[name] = source[name];
  572. });
  573. }
  574. }
  575. /**
  576. * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.
  577. */
  578. export function getLayoutParams(source) {
  579. return copyLayoutParams({}, source);
  580. }
  581. /**
  582. * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.
  583. * @param {Object} source
  584. * @return {Object} Result contains those props.
  585. */
  586. export function copyLayoutParams(target, source) {
  587. source && target && each(LOCATION_PARAMS, function (name) {
  588. zrUtil.hasOwn(source, name) && (target[name] = source[name]);
  589. });
  590. return target;
  591. }