Merge pull request #3343 from dataease/pr@dev@feat_map_gradient_color

feat(视图-地图): 增加渐变色方案
This commit is contained in:
Junjun 2022-10-12 16:14:17 +08:00 committed by GitHub
commit be18d50957
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1183 additions and 31 deletions

View File

@ -0,0 +1,666 @@
<template>
<div class="c__color-picker">
<el-popover
placement="bottom"
title=""
width="314"
poper-class=""
trigger="click"
v-model="visible"
@hide="whenHide"
>
<!-- 颜色面板 -->
<div class="" v-show="visible">
<div class="gradient-div">
<div class="gradient-check" :class="activeIndex === 0 ? 'active' : ''" @click="checkGradient(0)">
<div :style="{background: startColor}"></div>
</div>
<span class="gradient-div-span" :style="{background: gradientColor}" />
<div class="gradient-check" :class="activeIndex === 1 ? 'active' : ''" @click="checkGradient(1)">
<div :style="{background: endColor}"></div>
</div>
</div>
<!-- 画布 -->
<div class="c__canvas">
<canvas :id="canvasId" :width="width" :height="height" @click="onCanvasClick"
@mousedown="onCanvasMousedown"></canvas>
<!-- 当前选中小块 -->
<em class="c__cur" :id="curId" @mousedown="function(e){onCanvasMousedown(e,'cur')}"></em>
<!-- 左侧色条选中小块 -->
<em class="c__bar" :id="barId" @mousedown="function(e){onCanvasMousedown(e,'bar')}"></em>
<!-- 透明度控制条 -->
<div class="c__alpha-silder" v-if="showAlpha">
<div class="c__alpha-silder-bar" :style="alphaBarStyle" @click="onAlphaClick" @mousedown="onAlphaMousedown"></div>
<em class="c__alpha" :id="alphaId" :style="{left:alpha*100 + '%'}" @mousedown="onAlphaMousedown"></em>
</div>
</div>
<!-- 底部按钮栏 -->
<div class="c__control">
<input class="c__input" :value="innerValues[0]" />
<input class="c__input" :value="innerValues[1]" />
<div class="c__btns">
<div class="c__btn-clear" @click="curColor=''">清空</div>
<div class="c__btn-confirm" @click="confirm">确定</div>
</div>
</div>
</div>
<!-- 颜色显示方块 -->
<div class="c__block" slot="reference" :style="{background: formatBgColor(value)}" />
</el-popover>
</div>
</template>
<script>
export default {
name: "DeColorPicker",
props: {
/* 绑定的色值 */
value: {
type: Array,
default:['rgba(144,202,249,1)', 'rgba(1,87,155,1)']
},
/* 是否禁用 */
disabled: {
type: Boolean,
default: false
},
/* 是否使用透明度 */
showAlpha: {
type: Boolean,
default: false
},
/* 颜色类型可选值hexrgb */
colorFormat: {
type: String,
default: 'hex'
},
baseId: {
type: String,
default: ''
}
},
data() {
return {
canvasId: this.baseId + 'canvas-' + Date.now(), // id
curId: this.baseId + 'cur-' + Date.now(), // id
barId: this.baseId + 'bar-' + Date.now(), // id
alphaId: this.baseId + 'alpha-' + Date.now(), // id
canvas: null, //
ctx: null, //
curColor: '', //
activeColor: '', // bar
alpha: 1, //
width: 286, // canvas
height: 200, // canvas
activeIndex: 0,
innerValues: {
0: this.value[0],
1: this.value[1],
},
visible: false
}
},
computed:{
alphaBarStyle(){
return 'background: linear-gradient(to right, rgba(255, 69, 0, 0) 0%, ' + this.activeColor + ' 100%);';
},
startColor() {
return this.innerValues[0]
},
endColor() {
return this.innerValues[1]
},
gradientColor() {
return 'linear-gradient(90.0deg,'+this.innerValues[0]+' 0.0,'+this.innerValues[1]+' 100.0%)'
},
valueJson() {
return JSON.stringify(this.value)
}
},
watch: {
innerValues: {
handler(old, val) {
if(old === val) return
this.curColor = this.innerValues[this.activeIndex];
this.resetCurColor();
}
}
},
created() {
var _this = this;
JSON.parse(JSON.stringify(this.value)).forEach((item, index) => {
this.innerValues[index] = item
})
this.setAlpha()
this.handler = function(e) {
// _this.visible = false
}
document.body.addEventListener('click', this.handler)
this.$nextTick(() => {
this.curColor = this.innerValues[this.activeIndex];
this.activeColor = this.innerValues[this.activeIndex];
this.resetCurColor();
this.init();
})
},
beforeDestroy() {
document.body.removeEventListener('click', this.handler);
},
methods: {
setAlpha() {
const curColor = this.innerValues[this.activeIndex]
var reg = /^(rgb|RGB)/;
if (!reg.test(curColor)){
curColor = this.hex2rgb(curColor.slice(0,7));
}
var colorArr = curColor.replace(/(?:rgba|rgb|RGBA|RGB|\(|\))*/g, "").split(',');
if(colorArr.length === 4) {
this.alpha = colorArr[3]
return
}
this.alpha = 1
},
formatBgColor(color) {
return 'linear-gradient(0.0deg,' + color[0] + ' 0.0,' + color[1] + ' 100.0%)'
},
triggerHide() {
this.visible = false
},
whenHide() {
JSON.parse(JSON.stringify(this.value)).forEach((item, index) => {
this.innerValues[index] = item
})
this.$nextTick(() => {
this.curColor = this.innerValues[this.activeIndex];
this.activeColor = this.innerValues[this.activeIndex];
this.resetCurColor();
this.init();
})
},
/* 初始化 */
init() {
this.canvas = document.getElementById(this.canvasId);
this.$nextTick(() => {
this.ctx = this.canvas.getContext('2d');
this.makeColorBar();
this.makeColorBox(this.innerValues[this.activeIndex]);
})
},
/* 绘制左侧面板颜色选择条 */
makeColorBar() {
var gradientBar = this.ctx.createLinearGradient(0, 0, 0, this.height);
gradientBar.addColorStop(0, '#f00');
gradientBar.addColorStop(1 / 6, '#f0f');
gradientBar.addColorStop(2 / 6, '#00f');
gradientBar.addColorStop(3 / 6, '#0ff');
gradientBar.addColorStop(4 / 6, '#0f0');
gradientBar.addColorStop(5 / 6, '#ff0');
gradientBar.addColorStop(1, '#f00');
this.ctx.fillStyle = gradientBar;
this.ctx.fillRect(0, 0, 20, this.height);
},
/* 绘制颜色选择区域 */
makeColorBox(color) {
var gradientBase = this.ctx.createLinearGradient(30, 0, this.width, 0);
gradientBase.addColorStop(1, color);
gradientBase.addColorStop(0, 'rgba(255,255,255,1)');
this.ctx.fillStyle = gradientBase;
this.ctx.fillRect(30, 0, this.width, this.height);
var my_gradient1 = this.ctx.createLinearGradient(0, 0, 0, this.height);
my_gradient1.addColorStop(0, 'rgba(0,0,0,0)');
my_gradient1.addColorStop(1, 'rgba(0,0,0,1)');
this.ctx.fillStyle = my_gradient1;
this.ctx.fillRect(30, 0, this.width, this.height);
},
/* canvas点击 */
onCanvasClick(e) {
var ePos = {
x: e.offsetX || e.layerX,
y: e.offsetY || e.layerY
}
var rgbaStr = '#000';
if (ePos.x >= 0 && ePos.x < 20) {
// in
rgbaStr = this.getRgbaAtPoint(ePos, 'bar');
var barBlock = document.getElementById(this.barId);
barBlock.style.top = ePos.y + 'px';
this.makeColorBox('rgb(' + rgbaStr.slice(0, 3).join() + ')');
this.innerValues[this.activeIndex] ='rgba(' + rgbaStr.slice(0, 3).join() + ',' + this.alpha + ')'
this.$emit('active-change', this.innerValues);
} else if (ePos.x >= 30) {
rgbaStr = this.getRgbaAtPoint(ePos, 'box');
var cur = document.getElementById(this.curId);
cur.style.left = ePos.x + 'px';
cur.style.top = ePos.y + 'px';
} else {
return;
}
this.setCurColor(rgbaStr);
},
/* canvas鼠标按下绑定鼠标拖动函数 */
onCanvasMousedown(ev, type) {
var self = this;
var ePos = {
x: ev.layerX || ev.offsetX,
y: ev.layerY || ev.offsetY
}
var offsetTop = parseInt(ev.target.offsetTop);
var offsetLeft = parseInt(ev.target.offsetLeft);
if (type === 'cur' || (ePos.x >= 30 && ePos.x < 30 + this.width && ePos.y >= 0 && ePos.y < this.height)) {
var cur = document.getElementById(this.curId);
document.onmouseup = function() {
document.onmouseup = document.onmousemove = null;
}
document.onmousemove = function(e) {
try {
var pos = {
x: e.clientX - ev.clientX + ev.offsetX + offsetLeft,
y: e.clientY - ev.clientY + ev.offsetY + offsetTop
}
pos.x = pos.x <= 30 ? 30 : pos.x && (pos.x > self.width - 1 ? self.width - 1 : pos.x);
pos.y = pos.y <= 0 ? 0 : pos.y && (pos.y > self.height - 1 ? self.height - 1 : pos.y);
var rgbaStr = self.getRgbaAtPoint(pos, 'box');
self.setCurColor(rgbaStr);
cur.style.left = pos.x + 'px';
cur.style.top = pos.y + 'px';
} catch (e) {
}
}
} else if (ePos.x <= 20 && ePos.y <= this.height) {
var bar = document.getElementById(this.barId);
document.onmouseup = function() {
document.onmouseup = document.onmousemove = null;
}
document.onmousemove = function(e) {
try {
var pos = {
x: 0,
y: e.clientY - ev.clientY + ev.offsetY + offsetTop
}
pos.y = pos.y <= 0 ? 0 : pos.y && (pos.y > self.height - 1 ? self.height - 1 : pos
.y);
var rgbaStr = self.getRgbaAtPoint(pos, 'box');
bar.style.top = pos.y + 'px';
self.activeColor = 'rgb(' + rgbaStr.slice(0, 3).join() + ')';
self.makeColorBox('rgb(' + rgbaStr.slice(0, 3).join() + ')');
self.innerValues[self.activeIndex] = self.activeColor
self.$emit('active-change', self.innerValues);
} catch (e) {
}
}
}
},
/* 透明度控制条点击 */
onAlphaClick(e){
var x = e.offsetX || e.layerX;
var bar = document.getElementById(this.alphaId);
var parentNode = bar.parentNode;
this.alpha = parseFloat(x/parentNode.clientWidth).toFixed(2);
this.resetCurColor();
},
/* 透明度控制 */
onAlphaMousedown(ev){
var self = this;
var ePos = {
x: ev.layerX || ev.offsetX,
y: ev.layerY || ev.offsetY
}
var offsetTop = parseInt(ev.target.offsetTop);
var offsetLeft = parseInt(ev.target.offsetLeft);
var bar = document.getElementById(this.alphaId);
var parentNode = bar.parentNode;
document.onmouseup = function() {
document.onmouseup = document.onmousemove = null;
}
document.onmousemove = function(e) {
try {
var pos = {
x: e.clientX - ev.clientX + ev.offsetX + offsetLeft,
y: 0
}
pos.x = pos.x <= 0 ? 0 : pos.x && (pos.x > parentNode.clientWidth ? parentNode.clientWidth : pos
.x);
self.alpha = parseFloat(pos.x/parentNode.clientWidth).toFixed(2);
self.resetCurColor();
} catch (e) {
}
}
},
/* 透明度变化重新计算当前颜色值 */
resetCurColor(){
var curColor = this.curColor;
var alpha = this.alpha;
var reg = /^(rgb|RGB)/;
if (!reg.test(curColor)){
curColor = this.hex2rgb(curColor.slice(0,7));
}
var colorArr = curColor.replace(/(?:rgba|rgb|RGBA|RGB|\(|\))*/g, "").split(',');
colorArr[3] = alpha;
this.setCurColor(colorArr);
},
/* 设置当前颜色值 */
setCurColor(rgbaStr) {
var txt = 'a';
if (rgbaStr.length === 4 && parseFloat(rgbaStr[3]) === 1 || !this.showAlpha) {
rgbaStr = rgbaStr.slice(0, 3);
txt = '';
}
if (this.colorFormat === 'hex') {
this.curColor = this.rgb2hex('rgb' + txt + '(' + rgbaStr.join() + ')');
} else if (this.colorFormat === 'rgb') {
this.curColor = 'rgb' + txt + '(' + rgbaStr.join() + ')';
}
this.innerValues[this.activeIndex] = this.curColor
this.activeColor = this.innerValues[this.activeIndex];
this.sendChange();
},
/* 确认按钮点击 */
confirm() {
const values = []
Object.keys(this.innerValues).forEach(key => {
values.push(this.innerValues[key])
})
this.$emit('input', values);
this.visible = false
this.sendChange();
},
/* 触发change回调 */
sendChange() {
const values = []
Object.keys(this.innerValues).forEach(key => {
values.push(this.innerValues[key])
})
this.$emit('change', values);
},
/* 获取rgb */
getRgbaAtPoint(pos, area) {
if (area == 'bar') {
var imgData = this.ctx.getImageData(0, 0, 20, this.height);
} else {
var imgData = this.ctx.getImageData(0, 0, this.width, this.height);
}
var data = imgData.data;
var dataIndex = (pos.y * imgData.width + pos.x) * 4;
/* 开始消除误差 */
if (pos.x >= 30 && pos.y > this.height - 3) {
return [0, 0, 0, this.alpha];
}
if (pos.x >= 30 && pos.y <= 1) {
data[dataIndex] = 255;
}
if (pos.x >= 30 && pos.x <= 31) {
return [
data[dataIndex],
data[dataIndex],
data[dataIndex],
this.alpha
]
}
if (pos.x >= this.width - 1) {
return [
data[dataIndex],
0,
0,
this.alpha
]
}
/* 消除误差结束 */
return [
data[dataIndex],
data[dataIndex + 1],
data[dataIndex + 2],
this.alpha
];
},
/* rgb/rgba色值转16进制 */
rgb2hex(rgb) {
var reg = /^(rgb|RGB)/;
var a;
if (reg.test(rgb)) {
var colorArr = rgb.replace(/(?:rgba|rgb|RGBA|RGB|\(|\))*/g, "").split(',');
var alpha = (colorArr && colorArr[3] || "").trim()
var hex = "#" + ((1 << 24) + (parseInt(colorArr[0]) << 16) + (parseInt(colorArr[1]) << 8) + parseInt(
colorArr[2])).toString(16).slice(1);
if (alpha != '' && alpha != '1') {
a = ((alpha * 255) | 1 << 8).toString(16).slice(1);
hex = hex + a;
}
return hex;
} else {
return rgb
}
},
/* 16进制色值转rgb */
hex2rgb(hex) {
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
var color = hex.toLowerCase();
if (reg.test(color)) {
if (color.length === 4) {
var colorNew = "#";
for (var i = 1; i < color.length; i += 1) {
colorNew += color.slice(i, i + 1).concat(color.slice(i, i + 1));
}
color = colorNew;
}
var colorChange = [];
for (var i = 1; i < color.length; i += 2) {
colorChange.push(parseInt("0x" + color.slice(i, i + 2)));
}
return "rgb(" + colorChange.join(",") + ")";
} else {
return color;
}
},
checkGradient(index) {
this.activeIndex = index
this.curColor = this.innerValues[this.activeIndex];
this.activeColor = this.innerValues[this.activeIndex];
this.setAlpha()
this.$nextTick(() => {
this.resetCurColor();
this.init()
})
}
}
}
</script>
<style lang="scss">
.c__color-picker {
position: relative;
padding: 3px;
border: 1px solid #e6e6e6;
border-radius: 4px;
display: inline-block;
margin-right: 0px;
}
.c__block {
width: 18px;
height: 18px;
border-radius: 2px;
}
.c__panel {
// position: absolute;
top: 30px;
left: -137px;
z-index: 2001;
transform-origin: center top;
padding: 6px;
box-sizing: content-box;
background-color: #FFF;
border: 1px solid #EBEEF5;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
}
.c__canvas {
position: relative;
}
.c__canvas canvas {
left: 0;
top: 0;
}
.c__cur {
width: 3px;
height: 3px;
outline: 2px solid #fff;
margin-left: -1px;
margin-top: -1px;
position: absolute;
border-radius: 50%;
box-shadow: 0 0 0 1.5px #fff, inset 0 0 1px 1px rgb(0 0 0 / 30%), 0 0 1px 2px rgb(0 0 0 / 40%);
}
.c__bar,.c__alpha{
background-color: #fff;
position: absolute;
cursor: pointer;
border-radius: 1px;
border: 1px solid #f0f0f0;
box-shadow: 0 0 2px rgb(0 0 0 / 60%);
}
.c__bar {
width: 20px;
height: 3px;
left: 0;
top: 0;
}
.c__alpha{
width: 5px;
height: 20px;
left: 100%;
top: 0;
margin-left: -3px;
margin-top: -1px;
}
.c__alpha-silder {
position: relative;
box-sizing: border-box;
width: 100%;
height: 18px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
}
.c__alpha-silder-bar {
position: relative;
background: linear-gradient(to right, rgba(255, 69, 0, 0) 0%, rgb(255, 69, 0) 100%);
height: 100%;
}
.c__control {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 5px;
}
.c__input {
background-color: #FFF;
background-image: none;
border-radius: 4px;
border: 1px solid #DCDFE6;
box-sizing: border-box;
color: #606266;
display: inline-block;
outline: 0;
padding: 0 5px;
transition: border-color .2s cubic-bezier(.645, .045, .355, 1);
width: 130px;
font-size: 12px;
height: 28px;
line-height: 28px;
}
.c__input:focus {
border-color: #409EFF;
}
.c__btns {
display: flex;
justify-content: space-between;
align-items: center;
}
.c__btn-clear {
font-size: 12px;
color: #409EFF;
cursor: pointer;
display: none;
}
.c__btn-confirm {
padding: 7px 7px;
margin-left: 0px;
font-size: 12px;
border-radius: 3px;
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #FFF;
border: 1px solid #DCDFE6;
color: #606266;
text-align: center;
box-sizing: border-box;
outline: 0;
font-weight: 500;
&:hover {
border-color: var(--primary, #3370ff);
color: var(--primary, #3370ff);
}
}
.gradient-div {
width: 100%;
height: 30px;
padding-bottom: 5px;
display: flex;
.active {
border: 1px dashed var(--primary,#3370ff);
}
}
.gradient-div-span {
width: calc(100% - 60px);
height: 20px;
display: inline-block;
margin: 0 10px;
}
.gradient-check {
width: 20px;
height: 20px;
border-radius: 2px;
border: 1px solid #e6e6e6;
cursor: pointer;
div{
width: 16px;
height: 16px;
border-radius: 2px;
border: 1px solid #e6e6e6;
margin: 1px 1px;
}
}
</style>

View File

@ -0,0 +1,103 @@
import i18n from '@/lang'
export const colorCases = [
{
name: i18n.t('chart.color_default'),
value: 'default',
colors: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc']
},
{
name: i18n.t('chart.color_retro'),
value: 'retro',
colors: ['#0780cf', '#765005', '#fa6d1d', '#0e2c82', '#b6b51f', '#da1f18', '#701866', '#f47a75', '#009db2']
},
{
name: i18n.t('chart.color_elegant'),
value: 'elegant',
colors: ['#95a2ff', '#fa8080', '#ffc076', '#fae768', '#87e885', '#3cb9fc', '#73abf5', '#cb9bff', '#434348']
},
{
name: i18n.t('chart.color_future'),
value: 'future',
colors: ['#63b2ee', '#76da91', '#f8cb7f', '#f89588', '#7cd6cf', '#9192ab', '#7898e1', '#efa666', '#eddd86']
},
{
name: i18n.t('chart.color_gradual'),
value: 'gradual',
colors: ['#71ae46', '#96b744', '#c4cc38', '#ebe12a', '#eab026', '#e3852b', '#d85d2a', '#ce2626', '#ac2026']
},
{
name: i18n.t('chart.color_simple'),
value: 'simple',
colors: ['#929fff', '#9de0ff', '#ffa897', '#af87fe', '#7dc3fe', '#bb60b2', '#433e7c', '#f47a75', '#009db2']
},
{
name: i18n.t('chart.color_business'),
value: 'business',
colors: ['#194f97', '#555555', '#bd6b08', '#00686b', '#c82d31', '#625ba1', '#898989', '#9c9800', '#007f54']
},
{
name: i18n.t('chart.color_gentle'),
value: 'gentle',
colors: ['#5b9bd5', '#ed7d31', '#70ad47', '#ffc000', '#4472c4', '#91d024', '#b235e6', '#02ae75', '#5b9bd5']
},
{
name: i18n.t('chart.color_technology'),
value: 'technology',
colors: ['#05f8d6', '#0082fc', '#fdd845', '#22ed7c', '#09b0d3', '#1d27c9', '#f9e264', '#f47a75', '#009db2']
},
{
name: i18n.t('chart.color_light'),
value: 'light',
colors: ['#884898', '#808080', '#82ae46', '#00a3af', '#ef8b07', '#007bbb', '#9d775f', '#fae800', '#5f9b3c']
},
{
name: i18n.t('chart.color_classical'),
value: 'classical',
colors: ['#007bbb', '#ffdb4f', '#dd4b4b', '#2ca9e1', '#ef8b07', '#4a488e', '#82ae46', '#dd4b4b', '#bb9581']
},
{
name: i18n.t('chart.color_fresh'),
value: 'fresh',
colors: ['#5f9b3c', '#75c24b', '#83d65f', '#aacf53', '#c7dc68', '#d8e698', '#e0ebaf', '#bbc8e6', '#e5e5e5']
},
{
name: i18n.t('chart.color_energy'),
value: 'energy',
colors: ['#ef8b07', '#2a83a2', '#f07474', '#c55784', '#274a78', '#7058a3', '#0095d9', '#75c24b', '#808080']
},
{
name: i18n.t('chart.color_red'),
value: 'red',
colors: ['#ff0000', '#ef8b07', '#4c6cb3', '#f8e944', '#69821b', '#9c5ec3', '#00ccdf', '#f07474', '#bb9581']
},
{
name: i18n.t('chart.color_fast'),
value: 'fast',
colors: ['#fae800', '#00c039', '#0482dc', '#bb9581', '#ff7701', '#9c5ec3', '#00ccdf', '#00c039', '#ff7701']
},
{
name: i18n.t('chart.color_spiritual'),
value: 'spiritual',
colors: ['#00a3af', '#4da798', '#57baaa', '#62d0bd', '#6ee4d0', '#86e7d6', '#aeede1', '#bde1e6', '#e5e5e5']
}
]
export const gradientColorCases = [
{
name: '渐变色1',
value: 'gradient1',
colors: [
['rgba(144,202,249,0.5)', 'rgba(1,87,155,0.9)'],
['rgba(127,222,234,1)', 'rgba(0,77,65,1)'],
['rgba(129,199,132,1)', 'rgba(26,94,32,1)'],
['rgba(255,213,79,1)', 'rgba(230,81,0,1)'],
['rgba(186,105,200,1)', 'rgba(74,20,140,1)'],
['rgba(239,83,79,1)', 'rgba(152,10,11,1)']
]
}
]
export const isGradientValue = value => {
return value && gradientColorCases.some(item => item.value === value)
}

View File

@ -0,0 +1,324 @@
<template>
<div>
<div v-if="colorDto.value" class="color-div-base selected-div">
<div style="float: left;display: flex;align-items: center;">
<span v-for="(c,index) in colorDto.colors" :key="index" class="color-span-base" :style="{background: formatBgColor(c, true)}" />
</div>
<span style="margin-left: 4px;">
</span>
<span class="reset-span" @click="reset">
<el-tooltip class="item" effect="dark" content="重置" placement="top">
<i class="el-icon-refresh" />
</el-tooltip>
</span>
</div>
<el-popover
placement="bottom"
popper-class="gradient-popper"
:width="popWidth"
:append-to-body="true"
@show="whenShow"
trigger="click"
>
<div class="custom-switch-div">
<el-switch
v-model="enableCustom"
active-text="自定义"
inactive-text="">
</el-switch>
</div>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane v-for="(pane, i) in tabPanes" :key="i" :label="pane.label" :name="pane.name">
<div class="color-tab-content" :id="'color-tab-content-' + i" @click="handler">
<div v-for="option in pane.datas" :key="option.value" class="el-select-dropdown__item color-div-base" :class="option.value === colorDto.value ? 'selected hover editor' : ''" @click="selectNode(option)">
<div v-if="option.value !== colorDto.value || !enableCustom" style="float: left;display: flex;align-items: center;">
<span v-for="(c,index) in option.colors" :key="index" class="color-span-base" :style="{background: formatBgColor(c)}" />
</div>
<span v-if="option.value !== colorDto.value || !enableCustom" style="margin-left: 4px;">{{ option.name }}</span>
<span v-else v-for="(co,index) in option.colors" :key="index" class="color-span-base is-editor" >
<el-color-picker v-if="i === 0" v-model="option.colors[index]" @change="switchColorItem(option.colors, index)"/>
<de-color-picker ref="de-color-picker" :id="option.value + index" :base-id="option.value + index" show-alpha color-format="rgb" v-else v-model="option.colors[index]" @change="switchColorItem(option.colors, index)"/>
</span>
</div>
</div>
</el-tab-pane>
</el-tabs>
<el-select
ref="colorSelect"
slot="reference"
v-model="colorDto.value"
class="form-gender-select"
popper-class="gradient-tree-select"
:placeholder="$t('commons.please_select')"
@focus="_popoverShowFun"
>
<el-option
v-for="item in selectOptions"
:key="item.label"
:label="item.label"
:value="item.id"
/>
</el-select>
</el-popover>
</div>
</template>
<script>
import {colorCases, gradientColorCases} from './base'
import DeColorPicker from './DeColorPicker'
export default{
name: 'GradientColorSelector',
components: {
DeColorPicker
},
props: {
colorDto: {
type: Object,
default: () => {
return {
value: null,
colors: []
}
}
}
},
data() {
return {
value: null,
selectOptions: [],
popWidth: 260,
colorCases: JSON.parse(JSON.stringify(colorCases)),
gradientColorCases: JSON.parse(JSON.stringify(gradientColorCases)),
enableCustom: false,
activeName: 'simple',
tabPanes: [
{
label: '纯色',
name: 'simple',
datas: JSON.parse(JSON.stringify(colorCases))
},
{
label: '渐变',
name: 'gradient',
datas: JSON.parse(JSON.stringify(gradientColorCases))
}
],
testColor: '#5470c6'
}
},
computed: {
},
mounted() {
this._updateH()
},
created() {
this.initcolorDto()
},
methods: {
whenShow() {
this.$nextTick(() => {
this.initcolorDto()
this.scrollToSelected()
})
},
scrollToSelected() {
const index = this.activeName === 'simple' ? 0 : 1
const parents = document.getElementById("color-tab-content-" + index)
if(!parents) return
const items = parents.getElementsByClassName("color-div-base selected")
if(items && items.length) {
const top = items[0].offsetTop || 0
parents.scrollTo(0, top)
}
},
switchColorItem(colors, index) {
this.colorDto.colors = JSON.parse(JSON.stringify(colors))
this.$emit('color-change', JSON.parse(JSON.stringify(this.colorDto)))
},
initcolorDto() {
let haspPropValue = true
if (!this.colorDto.value) {
this.colorDto.value = this.colorCases[0].value
this.colorDto.colors = this.colorCases[0].colors
haspPropValue = false
}
this.activeName = this.colorCases.some(item => item.value === this.colorDto.value) ? 'simple' : 'gradient'
if(haspPropValue) {
this.tabPanes[this.activeName === 'simple' ? 0 : 1].datas.forEach(item => {
if (item.value === this.colorDto.value) {
item.colors = JSON.parse(JSON.stringify(this.colorDto.colors))
}
})
}
},
handler(e) {
const whiteClassName = 'c__block el-popover__reference'
if(!e || !e.target || !e.target.className) return
if(!this.$refs || !this.$refs['de-color-picker']) return
let id = null
if (e.target.className === whiteClassName) {
if(!e.target.parentElement || !e.target.parentElement.parentElement || !e.target.parentElement.parentElement.parentElement || !e.target.parentElement.parentElement.parentElement.id) return
id = e.target.parentElement.parentElement.parentElement.id
}
const widget = this.$refs['de-color-picker']
if (Array.isArray(widget)) {
widget.forEach(item => {
(!id || id !== item.$el.id) && item.triggerHide && item.triggerHide()
})
return
}
(!id || id !== widget.$el.id) && widget.triggerHide && widget.triggerHide()
},
handleClick() {
this.enableCustom = false
this.$nextTick(() => {
this.scrollToSelected()
})
const widget = this.$refs['de-color-picker']
if(!widget) return
if (Array.isArray(widget)) {
widget.forEach(item => {
item.triggerHide && item.triggerHide()
})
return
}
widget.triggerHide && widget.triggerHide()
},
_updateH() {
this.$nextTick(() => {
this.popWidth = this.$refs.colorSelect.$el.getBoundingClientRect().width
})
},
_popoverShowFun(val) {
this._updateH()
this.$emit('onFoucs')
},
fillGradientColor() {
this.gradientColorCases.forEach(item => {
item.colors = item.colors.map(color => {
const str = 'linear-gradient(0.0deg,' + color[0] + ' 0.0,' + color[1] + ' 100.0%)'
return str
})
})
this.tabPanes[1].datas = JSON.parse(JSON.stringify(this.gradientColorCases))
},
formatBgColor(color, useValue) {
let activeName = this.activeName
if(useValue) {
activeName = this.colorCases.some(item => item.value === this.colorDto.value) ? 'simple' : 'gradient'
}
if(activeName === 'simple') {
return color
}
return 'linear-gradient(0.0deg,' + color[0] + ' 0.0,' + color[1] + ' 100.0%)'
},
selectNode(option) {
this.selectOptions = [
{
id: option.value,
label: option.name,
colors: option.colors
}
]
this.colorDto.value = option.value
this.colorDto.colors = option.colors
this.$emit('color-change', JSON.parse(JSON.stringify(this.colorDto)))
},
reset() {
if(this.colorDto.value) {
let activeName = 'simple'
if(this.gradientColorCases.some(item => item.value === this.colorDto.value)) {
activeName = 'gradient'
}
(activeName === 'simple' ? colorCases : gradientColorCases).forEach(curcase => {
if(curcase.value === this.colorDto.value) {
this.colorDto.colors = JSON.parse(JSON.stringify(curcase.colors))
this.$emit('color-change', JSON.parse(JSON.stringify(this.colorDto)))
}
})
}
}
}
}
</script>
<style lang="scss">
.gradient-tree-select {
display: none !important;
}
.gradient-popper {
background: #fff;
padding: 0 10px;
margin-top: 1px !important;
border-top: none;
height: 300px;
.popper__arrow {
display: none;
}
.el-tabs__header {
margin: 0 0 2px !important;
}
}
.form-gender-select {
width: 100%;
.el-input__suffix {
display: none;
}
}
.color-span-base {
width: 20px;
height: 20px;
display:inline-block;
}
.is-editor {
width:23px !important;
height: 28px !important;
}
.color-div-base {
display: flex !important;
align-items: center !important;
cursor: pointer;
padding-left: 5px !important;
}
.custom-switch-div {
position: absolute;
top: 8px;
right: 10px;
z-index: 999;
}
.color-tab-content {
height: 255px;
overflow: auto;
.editor {
border: 1px dashed var(--primary,#3370ff);
}
}
.selected-div {
position: absolute;
z-index: 1;
top: 5px;
pointer-events: none;
.reset-span {
position: absolute;
left: 235px;
pointer-events: auto;
&:hover {
color: var(--primary,#3370ff);
}
}
}
</style>

View File

@ -1,14 +1,54 @@
// import { hexColorToRGBA } from '@/views/chart/chart/util'
import { componentStyle } from '../common/common'
import { BASE_ECHARTS_SELECT, DEFAULT_TOOLTIP } from '@/views/chart/chart/chart'
import { isGradientValue } from '@/components/GradientColorSelector/base'
const linearCOlor = (start, end) => {
return {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{offset: 0, color: start},
{offset: 1, color: end},
],
global: false
}
}
const fillGradientColor = (data, colors) => {
if(!data || !data.length) return data
const dataLen = data.length
const colorLen = colors.length
data.forEach((item, index) => {
const colorIndex = index % colorLen
const colorArr = colors[colorIndex]
if(Array.isArray(colorArr)) {
item.itemStyle = {
normal: {
areaColor: linearCOlor(colorArr[0], colorArr[1]),
opacity: 0.6
},
emphasis: {
areaColor: linearCOlor(colorArr[0], colorArr[1]),
opacity: 1
}
}
}
})
return data
}
export function baseMapOption(chart_option, chart, themeStyle, curAreaCode) {
// 处理shape attr
let customAttr = {}
let isGradient = false
if (chart.customAttr) {
customAttr = JSON.parse(chart.customAttr)
if (customAttr.color) {
chart_option.color = customAttr.color.colors
const colorValue = customAttr.color.value
isGradient = isGradientValue(colorValue)
// chart_option.color = customAttr.color.colors
if (customAttr.color.areaBorderColor) {
chart_option.series[0].itemStyle.normal.borderColor = customAttr.color.areaBorderColor
}
@ -57,38 +97,48 @@ export function baseMapOption(chart_option, chart, themeStyle, curAreaCode) {
chart_option.series[0].label.showdowColor = customAttr.label.shadowColor
}
}
// visualMap
const valueArr = chart.data.series[0].data
if (valueArr && valueArr.length > 0) {
const values = []
valueArr.forEach(function(ele) {
values.push(ele.value)
})
chart_option.visualMap.min = Math.min(...values)
chart_option.visualMap.max = Math.max(...values)
if (chart_option.visualMap.min === chart_option.visualMap.max) {
// visualMap
if(!isGradient) {
if (valueArr && valueArr.length > 0) {
const values = []
valueArr.forEach(function(ele) {
values.push(ele.value)
})
chart_option.visualMap.min = Math.min(...values)
chart_option.visualMap.max = Math.max(...values)
if (chart_option.visualMap.min === chart_option.visualMap.max) {
chart_option.visualMap.min = 0
}
} else {
chart_option.visualMap.min = 0
chart_option.visualMap.max = 0
}
if (chart_option.visualMap.min === 0 && chart_option.visualMap.max === 0) {
chart_option.visualMap.max = 100
}
// color
if (customAttr.color && customAttr.color.colors) {
chart_option.visualMap.inRange.color = customAttr.color.colors
chart_option.visualMap.inRange.colorAlpha = customAttr.color.alpha / 100
}
if (themeStyle) {
chart_option.visualMap.textStyle = { color: themeStyle }
}
} else {
chart_option.visualMap.min = 0
chart_option.visualMap.max = 0
}
if (chart_option.visualMap.min === 0 && chart_option.visualMap.max === 0) {
chart_option.visualMap.max = 100
}
// color
if (customAttr.color && customAttr.color.colors) {
chart_option.visualMap.inRange.color = customAttr.color.colors
chart_option.visualMap.inRange.colorAlpha = customAttr.color.alpha / 100
}
if (themeStyle) {
chart_option.visualMap.textStyle = { color: themeStyle }
}
for (let i = 0; i < valueArr.length; i++) {
const y = valueArr[i]
y.name = chart.data.x[i]
chart_option.series[0].data.push(y)
}
if (isGradient) {
chart_option.series[0].data = fillGradientColor(chart_option.series[0].data, customAttr.color.colors)
delete chart_option.visualMap
}
if (chart.senior) {
const senior = JSON.parse(chart.senior)

View File

@ -2760,7 +2760,8 @@ export const TYPE_CONFIGS = [
'value',
'custom',
'alpha',
'area-border-color'
'area-border-color',
'gradient-color'
],
'label-selector': [
'show',

View File

@ -8,11 +8,10 @@
size="mini"
>
<div>
<el-form-item
v-show="showProperty('value')"
:label="$t('chart.color_case')"
class="form-item"
>
<el-form-item v-show="showProperty('value') && showProperty('gradient-color')" :label="$t('chart.color_case')" class="form-item">
<gradient-color-selector :color-dto="colorForm" @color-change="gradientColorChange"/>
</el-form-item>
<el-form-item v-show="showProperty('value') && !showProperty('gradient-color')" :label="$t('chart.color_case')" class="form-item">
<el-popover
placement="bottom"
width="400"
@ -263,10 +262,12 @@
import { COLOR_PANEL, DEFAULT_COLOR_CASE } from '../../chart/chart'
import { getColors } from '@/views/chart/chart/util'
import { mapState } from 'vuex'
import GradientColorSelector from '@/components/GradientColorSelector'
import bus from '@/utils/bus'
export default {
name: 'ColorSelector',
components: {GradientColorSelector},
props: {
param: {
type: Object,
@ -406,6 +407,13 @@ export default {
bus.$off('prop-change-data', this.initCustomColor)
},
methods: {
gradientColorChange(colorDto) {
const modifyNames = ['value', 'colors', 'seriesColors']
modifyNames.forEach(item => {
this.colorForm['modifyName'] = item
this.$emit('onColorChange', this.colorForm)
})
},
changeColorOption(modifyName = 'value') {
const that = this
const items = this.colorCases.filter(ele => {