123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 |
- /*
- * 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.
- */
- var echarts = require("../../echarts");
- var zrUtil = require("zrender/lib/core/util");
- var env = require("zrender/lib/core/env");
- var visualDefault = require("../../visual/visualDefault");
- var VisualMapping = require("../../visual/VisualMapping");
- var visualSolution = require("../../visual/visualSolution");
- var modelUtil = require("../../util/model");
- var numberUtil = require("../../util/number");
- /*
- * 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.
- */
- var mapVisual = VisualMapping.mapVisual;
- var eachVisual = VisualMapping.eachVisual;
- var isArray = zrUtil.isArray;
- var each = zrUtil.each;
- var asc = numberUtil.asc;
- var linearMap = numberUtil.linearMap;
- var noop = zrUtil.noop;
- var VisualMapModel = echarts.extendComponentModel({
- type: 'visualMap',
- dependencies: ['series'],
- /**
- * @readOnly
- * @type {Array.<string>}
- */
- stateList: ['inRange', 'outOfRange'],
- /**
- * @readOnly
- * @type {Array.<string>}
- */
- replacableOptionKeys: ['inRange', 'outOfRange', 'target', 'controller', 'color'],
- /**
- * [lowerBound, upperBound]
- *
- * @readOnly
- * @type {Array.<number>}
- */
- dataBound: [-Infinity, Infinity],
- /**
- * @readOnly
- * @type {string|Object}
- */
- layoutMode: {
- type: 'box',
- ignoreSize: true
- },
- /**
- * @protected
- */
- defaultOption: {
- show: true,
- zlevel: 0,
- z: 4,
- seriesIndex: 'all',
- // 'all' or null/undefined: all series.
- // A number or an array of number: the specified series.
- // set min: 0, max: 200, only for campatible with ec2.
- // In fact min max should not have default value.
- min: 0,
- // min value, must specified if pieces is not specified.
- max: 200,
- // max value, must specified if pieces is not specified.
- dimension: null,
- inRange: null,
- // 'color', 'colorHue', 'colorSaturation', 'colorLightness', 'colorAlpha',
- // 'symbol', 'symbolSize'
- outOfRange: null,
- // 'color', 'colorHue', 'colorSaturation',
- // 'colorLightness', 'colorAlpha',
- // 'symbol', 'symbolSize'
- left: 0,
- // 'center' ¦ 'left' ¦ 'right' ¦ {number} (px)
- right: null,
- // The same as left.
- top: null,
- // 'top' ¦ 'bottom' ¦ 'center' ¦ {number} (px)
- bottom: 0,
- // The same as top.
- itemWidth: null,
- itemHeight: null,
- inverse: false,
- orient: 'vertical',
- // 'horizontal' ¦ 'vertical'
- backgroundColor: 'rgba(0,0,0,0)',
- borderColor: '#ccc',
- // 值域边框颜色
- contentColor: '#5793f3',
- inactiveColor: '#aaa',
- borderWidth: 0,
- // 值域边框线宽,单位px,默认为0(无边框)
- padding: 5,
- // 值域内边距,单位px,默认各方向内边距为5,
- // 接受数组分别设定上右下左边距,同css
- textGap: 10,
- //
- precision: 0,
- // 小数精度,默认为0,无小数点
- color: null,
- //颜色(deprecated,兼容ec2,顺序同pieces,不同于inRange/outOfRange)
- formatter: null,
- text: null,
- // 文本,如['高', '低'],兼容ec2,text[0]对应高值,text[1]对应低值
- textStyle: {
- color: '#333' // 值域文字颜色
- }
- },
- /**
- * @protected
- */
- init: function (option, parentModel, ecModel) {
- /**
- * @private
- * @type {Array.<number>}
- */
- this._dataExtent;
- /**
- * @readOnly
- */
- this.targetVisuals = {};
- /**
- * @readOnly
- */
- this.controllerVisuals = {};
- /**
- * @readOnly
- */
- this.textStyleModel;
- /**
- * [width, height]
- * @readOnly
- * @type {Array.<number>}
- */
- this.itemSize;
- this.mergeDefaultAndTheme(option, ecModel);
- },
- /**
- * @protected
- */
- optionUpdated: function (newOption, isInit) {
- var thisOption = this.option; // FIXME
- // necessary?
- // Disable realtime view update if canvas is not supported.
- if (!env.canvasSupported) {
- thisOption.realtime = false;
- }
- !isInit && visualSolution.replaceVisualOption(thisOption, newOption, this.replacableOptionKeys);
- this.textStyleModel = this.getModel('textStyle');
- this.resetItemSize();
- this.completeVisualOption();
- },
- /**
- * @protected
- */
- resetVisual: function (supplementVisualOption) {
- var stateList = this.stateList;
- supplementVisualOption = zrUtil.bind(supplementVisualOption, this);
- this.controllerVisuals = visualSolution.createVisualMappings(this.option.controller, stateList, supplementVisualOption);
- this.targetVisuals = visualSolution.createVisualMappings(this.option.target, stateList, supplementVisualOption);
- },
- /**
- * @protected
- * @return {Array.<number>} An array of series indices.
- */
- getTargetSeriesIndices: function () {
- var optionSeriesIndex = this.option.seriesIndex;
- var seriesIndices = [];
- if (optionSeriesIndex == null || optionSeriesIndex === 'all') {
- this.ecModel.eachSeries(function (seriesModel, index) {
- seriesIndices.push(index);
- });
- } else {
- seriesIndices = modelUtil.normalizeToArray(optionSeriesIndex);
- }
- return seriesIndices;
- },
- /**
- * @public
- */
- eachTargetSeries: function (callback, context) {
- zrUtil.each(this.getTargetSeriesIndices(), function (seriesIndex) {
- callback.call(context, this.ecModel.getSeriesByIndex(seriesIndex));
- }, this);
- },
- /**
- * @pubilc
- */
- isTargetSeries: function (seriesModel) {
- var is = false;
- this.eachTargetSeries(function (model) {
- model === seriesModel && (is = true);
- });
- return is;
- },
- /**
- * @example
- * this.formatValueText(someVal); // format single numeric value to text.
- * this.formatValueText(someVal, true); // format single category value to text.
- * this.formatValueText([min, max]); // format numeric min-max to text.
- * this.formatValueText([this.dataBound[0], max]); // using data lower bound.
- * this.formatValueText([min, this.dataBound[1]]); // using data upper bound.
- *
- * @param {number|Array.<number>} value Real value, or this.dataBound[0 or 1].
- * @param {boolean} [isCategory=false] Only available when value is number.
- * @param {Array.<string>} edgeSymbols Open-close symbol when value is interval.
- * @return {string}
- * @protected
- */
- formatValueText: function (value, isCategory, edgeSymbols) {
- var option = this.option;
- var precision = option.precision;
- var dataBound = this.dataBound;
- var formatter = option.formatter;
- var isMinMax;
- var textValue;
- edgeSymbols = edgeSymbols || ['<', '>'];
- if (zrUtil.isArray(value)) {
- value = value.slice();
- isMinMax = true;
- }
- textValue = isCategory ? value : isMinMax ? [toFixed(value[0]), toFixed(value[1])] : toFixed(value);
- if (zrUtil.isString(formatter)) {
- return formatter.replace('{value}', isMinMax ? textValue[0] : textValue).replace('{value2}', isMinMax ? textValue[1] : textValue);
- } else if (zrUtil.isFunction(formatter)) {
- return isMinMax ? formatter(value[0], value[1]) : formatter(value);
- }
- if (isMinMax) {
- if (value[0] === dataBound[0]) {
- return edgeSymbols[0] + ' ' + textValue[1];
- } else if (value[1] === dataBound[1]) {
- return edgeSymbols[1] + ' ' + textValue[0];
- } else {
- return textValue[0] + ' - ' + textValue[1];
- }
- } else {
- // Format single value (includes category case).
- return textValue;
- }
- function toFixed(val) {
- return val === dataBound[0] ? 'min' : val === dataBound[1] ? 'max' : (+val).toFixed(Math.min(precision, 20));
- }
- },
- /**
- * @protected
- */
- resetExtent: function () {
- var thisOption = this.option; // Can not calculate data extent by data here.
- // Because series and data may be modified in processing stage.
- // So we do not support the feature "auto min/max".
- var extent = asc([thisOption.min, thisOption.max]);
- this._dataExtent = extent;
- },
- /**
- * @public
- * @param {module:echarts/data/List} list
- * @return {string} Concrete dimention. If return null/undefined,
- * no dimension used.
- */
- getDataDimension: function (list) {
- var optDim = this.option.dimension;
- var listDimensions = list.dimensions;
- if (optDim == null && !listDimensions.length) {
- return;
- }
- if (optDim != null) {
- return list.getDimension(optDim);
- }
- var dimNames = list.dimensions;
- for (var i = dimNames.length - 1; i >= 0; i--) {
- var dimName = dimNames[i];
- var dimInfo = list.getDimensionInfo(dimName);
- if (!dimInfo.isCalculationCoord) {
- return dimName;
- }
- }
- },
- /**
- * @public
- * @override
- */
- getExtent: function () {
- return this._dataExtent.slice();
- },
- /**
- * @protected
- */
- completeVisualOption: function () {
- var ecModel = this.ecModel;
- var thisOption = this.option;
- var base = {
- inRange: thisOption.inRange,
- outOfRange: thisOption.outOfRange
- };
- var target = thisOption.target || (thisOption.target = {});
- var controller = thisOption.controller || (thisOption.controller = {});
- zrUtil.merge(target, base); // Do not override
- zrUtil.merge(controller, base); // Do not override
- var isCategory = this.isCategory();
- completeSingle.call(this, target);
- completeSingle.call(this, controller);
- completeInactive.call(this, target, 'inRange', 'outOfRange'); // completeInactive.call(this, target, 'outOfRange', 'inRange');
- completeController.call(this, controller);
- function completeSingle(base) {
- // Compatible with ec2 dataRange.color.
- // The mapping order of dataRange.color is: [high value, ..., low value]
- // whereas inRange.color and outOfRange.color is [low value, ..., high value]
- // Notice: ec2 has no inverse.
- if (isArray(thisOption.color) // If there has been inRange: {symbol: ...}, adding color is a mistake.
- // So adding color only when no inRange defined.
- && !base.inRange) {
- base.inRange = {
- color: thisOption.color.slice().reverse()
- };
- } // Compatible with previous logic, always give a defautl color, otherwise
- // simple config with no inRange and outOfRange will not work.
- // Originally we use visualMap.color as the default color, but setOption at
- // the second time the default color will be erased. So we change to use
- // constant DEFAULT_COLOR.
- // If user do not want the default color, set inRange: {color: null}.
- base.inRange = base.inRange || {
- color: ecModel.get('gradientColor')
- }; // If using shortcut like: {inRange: 'symbol'}, complete default value.
- each(this.stateList, function (state) {
- var visualType = base[state];
- if (zrUtil.isString(visualType)) {
- var defa = visualDefault.get(visualType, 'active', isCategory);
- if (defa) {
- base[state] = {};
- base[state][visualType] = defa;
- } else {
- // Mark as not specified.
- delete base[state];
- }
- }
- }, this);
- }
- function completeInactive(base, stateExist, stateAbsent) {
- var optExist = base[stateExist];
- var optAbsent = base[stateAbsent];
- if (optExist && !optAbsent) {
- optAbsent = base[stateAbsent] = {};
- each(optExist, function (visualData, visualType) {
- if (!VisualMapping.isValidType(visualType)) {
- return;
- }
- var defa = visualDefault.get(visualType, 'inactive', isCategory);
- if (defa != null) {
- optAbsent[visualType] = defa; // Compatibable with ec2:
- // Only inactive color to rgba(0,0,0,0) can not
- // make label transparent, so use opacity also.
- if (visualType === 'color' && !optAbsent.hasOwnProperty('opacity') && !optAbsent.hasOwnProperty('colorAlpha')) {
- optAbsent.opacity = [0, 0];
- }
- }
- });
- }
- }
- function completeController(controller) {
- var symbolExists = (controller.inRange || {}).symbol || (controller.outOfRange || {}).symbol;
- var symbolSizeExists = (controller.inRange || {}).symbolSize || (controller.outOfRange || {}).symbolSize;
- var inactiveColor = this.get('inactiveColor');
- each(this.stateList, function (state) {
- var itemSize = this.itemSize;
- var visuals = controller[state]; // Set inactive color for controller if no other color
- // attr (like colorAlpha) specified.
- if (!visuals) {
- visuals = controller[state] = {
- color: isCategory ? inactiveColor : [inactiveColor]
- };
- } // Consistent symbol and symbolSize if not specified.
- if (visuals.symbol == null) {
- visuals.symbol = symbolExists && zrUtil.clone(symbolExists) || (isCategory ? 'roundRect' : ['roundRect']);
- }
- if (visuals.symbolSize == null) {
- visuals.symbolSize = symbolSizeExists && zrUtil.clone(symbolSizeExists) || (isCategory ? itemSize[0] : [itemSize[0], itemSize[0]]);
- } // Filter square and none.
- visuals.symbol = mapVisual(visuals.symbol, function (symbol) {
- return symbol === 'none' || symbol === 'square' ? 'roundRect' : symbol;
- }); // Normalize symbolSize
- var symbolSize = visuals.symbolSize;
- if (symbolSize != null) {
- var max = -Infinity; // symbolSize can be object when categories defined.
- eachVisual(symbolSize, function (value) {
- value > max && (max = value);
- });
- visuals.symbolSize = mapVisual(symbolSize, function (value) {
- return linearMap(value, [0, max], [0, itemSize[0]], true);
- });
- }
- }, this);
- }
- },
- /**
- * @protected
- */
- resetItemSize: function () {
- this.itemSize = [parseFloat(this.get('itemWidth')), parseFloat(this.get('itemHeight'))];
- },
- /**
- * @public
- */
- isCategory: function () {
- return !!this.option.categories;
- },
- /**
- * @public
- * @abstract
- */
- setSelected: noop,
- /**
- * @public
- * @abstract
- * @param {*|module:echarts/data/List} valueOrData
- * @param {number} dataIndex
- * @return {string} state See this.stateList
- */
- getValueState: noop,
- /**
- * FIXME
- * Do not publish to thirt-part-dev temporarily
- * util the interface is stable. (Should it return
- * a function but not visual meta?)
- *
- * @pubilc
- * @abstract
- * @param {Function} getColorVisual
- * params: value, valueState
- * return: color
- * @return {Object} visualMeta
- * should includes {stops, outerColors}
- * outerColor means [colorBeyondMinValue, colorBeyondMaxValue]
- */
- getVisualMeta: noop
- });
- var _default = VisualMapModel;
- module.exports = _default;
|