forked from github/dataease
Merge pull request #13019 from dataease/pr@dev-v2@feat_symbol_map_custom_image_icon
feat(图表): 符号地图自定义符号支持图片
This commit is contained in:
commit
c8f7ffb18b
@ -76,7 +76,12 @@ const init = () => {
|
|||||||
basicStyle.mapSymbol === 'custom' &&
|
basicStyle.mapSymbol === 'custom' &&
|
||||||
state.basicStyleForm.customIcon !== basicStyle.customIcon
|
state.basicStyleForm.customIcon !== basicStyle.customIcon
|
||||||
) {
|
) {
|
||||||
const file = svgStrToUrl(basicStyle.customIcon)
|
let file
|
||||||
|
if (basicStyle.customIcon?.startsWith('data')) {
|
||||||
|
file = basicStyle.customIcon
|
||||||
|
} else {
|
||||||
|
file = svgStrToUrl(basicStyle.customIcon)
|
||||||
|
}
|
||||||
file && (state.fileList[0] = { url: file })
|
file && (state.fileList[0] = { url: file })
|
||||||
}
|
}
|
||||||
state.basicStyleForm = defaultsDeep(basicStyle, cloneDeep(DEFAULT_BASIC_STYLE)) as ChartBasicStyle
|
state.basicStyleForm = defaultsDeep(basicStyle, cloneDeep(DEFAULT_BASIC_STYLE)) as ChartBasicStyle
|
||||||
@ -243,11 +248,12 @@ const mapSymbolOptions = [
|
|||||||
{ name: t('commons.custom'), value: 'custom' }
|
{ name: t('commons.custom'), value: 'custom' }
|
||||||
]
|
]
|
||||||
const iconUpload = ref()
|
const iconUpload = ref()
|
||||||
|
const acceptedFileType = ['image/svg+xml', 'image/jpeg', 'image/png']
|
||||||
const onIconChange: UploadProps['onChange'] = async uploadFile => {
|
const onIconChange: UploadProps['onChange'] = async uploadFile => {
|
||||||
const rawFile = uploadFile.raw
|
const rawFile = uploadFile.raw
|
||||||
let validIcon = true
|
let validIcon = true
|
||||||
if (rawFile.type !== 'image/svg+xml') {
|
if (!acceptedFileType.includes(rawFile.type)) {
|
||||||
ElMessage.error('请选择正确的 SVG 文件!')
|
ElMessage.error('请选择正确的图标文件!')
|
||||||
validIcon = false
|
validIcon = false
|
||||||
}
|
}
|
||||||
if (rawFile.size / 1024 / 1024 > 1) {
|
if (rawFile.size / 1024 / 1024 > 1) {
|
||||||
@ -257,20 +263,42 @@ const onIconChange: UploadProps['onChange'] = async uploadFile => {
|
|||||||
if (!validIcon) {
|
if (!validIcon) {
|
||||||
iconUpload.value?.clearFiles()
|
iconUpload.value?.clearFiles()
|
||||||
state.fileList.splice(0)
|
state.fileList.splice(0)
|
||||||
const svg = state.basicStyleForm.customIcon
|
const customIcon = state.basicStyleForm.customIcon
|
||||||
if (svg) {
|
if (customIcon) {
|
||||||
const file = svgStrToUrl(svg)
|
let file = ''
|
||||||
|
// 图片
|
||||||
|
if (customIcon.startsWith('data')) {
|
||||||
|
file = customIcon
|
||||||
|
} else {
|
||||||
|
// svg
|
||||||
|
file = svgStrToUrl(customIcon)
|
||||||
|
}
|
||||||
file && (state.fileList[0] = { url: file })
|
file && (state.fileList[0] = { url: file })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.basicStyleForm.customIcon = await rawFile.text()
|
if (rawFile.type === 'image/svg+xml') {
|
||||||
changeBasicStyle('customIcon')
|
state.basicStyleForm.customIcon = await rawFile.text()
|
||||||
|
changeBasicStyle('customIcon')
|
||||||
|
} else {
|
||||||
|
const fileReader = new FileReader()
|
||||||
|
fileReader.onloadend = () => {
|
||||||
|
state.basicStyleForm.customIcon = fileReader.result as string
|
||||||
|
changeBasicStyle('customIcon')
|
||||||
|
}
|
||||||
|
fileReader.readAsDataURL(rawFile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeMapSymbol = () => {
|
const changeMapSymbol = () => {
|
||||||
if (state.basicStyleForm.mapSymbol === 'custom' && state.basicStyleForm.customIcon) {
|
const { mapSymbol, customIcon } = state.basicStyleForm
|
||||||
const file = svgStrToUrl(state.basicStyleForm.customIcon)
|
if (mapSymbol === 'custom' && customIcon) {
|
||||||
|
let file
|
||||||
|
if (customIcon.startsWith('data')) {
|
||||||
|
file = customIcon
|
||||||
|
} else {
|
||||||
|
file = svgStrToUrl(state.basicStyleForm.customIcon)
|
||||||
|
}
|
||||||
file && (state.fileList[0] = { url: file })
|
file && (state.fileList[0] = { url: file })
|
||||||
}
|
}
|
||||||
changeBasicStyle('mapSymbol')
|
changeBasicStyle('mapSymbol')
|
||||||
@ -521,12 +549,12 @@ onMounted(() => {
|
|||||||
<el-row style="flex: 1">
|
<el-row style="flex: 1">
|
||||||
<el-col>
|
<el-col>
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<template v-if="state.basicStyleForm.mapSymbol === 'custom'" #label>
|
<template #label>
|
||||||
<span class="data-area-label">
|
<span class="data-area-label">
|
||||||
<span style="margin-right: 4px">符号形状</span>
|
<span style="margin-right: 4px">符号形状</span>
|
||||||
<el-tooltip class="item" effect="dark" placement="bottom">
|
<el-tooltip class="item" effect="dark" placement="bottom">
|
||||||
<template #content>
|
<template v-if="state.basicStyleForm.mapSymbol === 'custom'" #content>
|
||||||
<div>支持 1MB 以内的 SVG 文件</div>
|
<div>支持 1MB 以内的 SVG, JPG, JPEG, PNG 文件</div>
|
||||||
</template>
|
</template>
|
||||||
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
|
<el-icon class="hint-icon" :class="{ 'hint-icon--dark': themes === 'dark' }">
|
||||||
<Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon>
|
<Icon name="icon_info_outlined"><icon_info_outlined class="svg-icon" /></Icon>
|
||||||
@ -555,7 +583,7 @@ onMounted(() => {
|
|||||||
<div class="avatar-uploader-container" :class="`img-area_${themes}`">
|
<div class="avatar-uploader-container" :class="`img-area_${themes}`">
|
||||||
<el-upload
|
<el-upload
|
||||||
action="#"
|
action="#"
|
||||||
accept=".svg"
|
accept=".svg,.png,.jpeg,.jpg"
|
||||||
class="avatar-uploader"
|
class="avatar-uploader"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
ref="iconUpload"
|
ref="iconUpload"
|
||||||
|
@ -241,19 +241,27 @@ export class SymbolicMap extends L7ChartView<Scene, L7Config> {
|
|||||||
.active(true)
|
.active(true)
|
||||||
if (xAxisExt[0]?.dataeaseName) {
|
if (xAxisExt[0]?.dataeaseName) {
|
||||||
if (basicStyle.mapSymbol === 'custom' && basicStyle.customIcon) {
|
if (basicStyle.mapSymbol === 'custom' && basicStyle.customIcon) {
|
||||||
const parser = new DOMParser()
|
// 图片无法改色
|
||||||
for (let index = 0; index < Math.min(colorsWithAlpha.length, colorIndex + 1); index++) {
|
if (basicStyle.customIcon.startsWith('data')) {
|
||||||
const color = colorsWithAlpha[index]
|
scene.removeImage('customIcon')
|
||||||
const fillRegex = /(fill="[^"]*")/g
|
await scene.addImage('customIcon', basicStyle.customIcon)
|
||||||
const svgStr = basicStyle.customIcon.replace(fillRegex, '')
|
pointLayer.shape('customIcon')
|
||||||
const doc = parser.parseFromString(svgStr, 'image/svg+xml')
|
} else {
|
||||||
const svgEle = doc.documentElement
|
const parser = new DOMParser()
|
||||||
svgEle.setAttribute('fill', color)
|
for (let index = 0; index < Math.min(colorsWithAlpha.length, colorIndex + 1); index++) {
|
||||||
await scene.addImage(`icon-${color}`, svgStrToUrl(svgEle.outerHTML))
|
const color = colorsWithAlpha[index]
|
||||||
|
const fillRegex = /(fill="[^"]*")/g
|
||||||
|
const svgStr = basicStyle.customIcon.replace(fillRegex, '')
|
||||||
|
const doc = parser.parseFromString(svgStr, 'image/svg+xml')
|
||||||
|
const svgEle = doc.documentElement
|
||||||
|
svgEle.setAttribute('fill', color)
|
||||||
|
scene.removeImage(`icon-${color}`)
|
||||||
|
await scene.addImage(`icon-${color}`, svgStrToUrl(svgEle.outerHTML))
|
||||||
|
}
|
||||||
|
pointLayer.shape('color', c => {
|
||||||
|
return `icon-${c}`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pointLayer.shape('color', c => {
|
|
||||||
return `icon-${c}`
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
pointLayer.shape(mapSymbol).color(xAxisExt[0]?.dataeaseName, colorsWithAlpha)
|
pointLayer.shape(mapSymbol).color(xAxisExt[0]?.dataeaseName, colorsWithAlpha)
|
||||||
pointLayer.style({
|
pointLayer.style({
|
||||||
@ -266,23 +274,30 @@ export class SymbolicMap extends L7ChartView<Scene, L7Config> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (basicStyle.mapSymbol === 'custom' && basicStyle.customIcon) {
|
if (basicStyle.mapSymbol === 'custom' && basicStyle.customIcon) {
|
||||||
const parser = new DOMParser()
|
scene.removeImage('customIcon')
|
||||||
const color = colorsWithAlpha[0]
|
if (basicStyle.customIcon.startsWith('data')) {
|
||||||
const fillRegex = /(fill="[^"]*")/g
|
await scene.addImage('customIcon', basicStyle.customIcon)
|
||||||
const svgStr = basicStyle.customIcon.replace(fillRegex, '')
|
pointLayer.shape('customIcon')
|
||||||
const doc = parser.parseFromString(svgStr, 'image/svg+xml')
|
} else {
|
||||||
const svgEle = doc.documentElement
|
const parser = new DOMParser()
|
||||||
svgEle.setAttribute('fill', color)
|
const color = colorsWithAlpha[0]
|
||||||
await scene.addImage(`customIcon`, svgStrToUrl(svgEle.outerHTML))
|
const fillRegex = /(fill="[^"]*")/g
|
||||||
pointLayer.shape('customIcon')
|
const svgStr = basicStyle.customIcon.replace(fillRegex, '')
|
||||||
|
const doc = parser.parseFromString(svgStr, 'image/svg+xml')
|
||||||
|
const svgEle = doc.documentElement
|
||||||
|
svgEle.setAttribute('fill', color)
|
||||||
|
await scene.addImage(`customIcon`, svgStrToUrl(svgEle.outerHTML))
|
||||||
|
pointLayer.shape('customIcon')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pointLayer.shape(mapSymbol)
|
pointLayer
|
||||||
pointLayer.color(colorsWithAlpha[0])
|
.shape(mapSymbol)
|
||||||
pointLayer.style({
|
.color(colorsWithAlpha[0])
|
||||||
stroke: colorsWithAlpha[0],
|
.style({
|
||||||
strokeWidth: mapSymbolStrokeWidth,
|
stroke: colorsWithAlpha[0],
|
||||||
opacity: mapSymbolOpacity / 10
|
strokeWidth: mapSymbolStrokeWidth,
|
||||||
})
|
opacity: mapSymbolOpacity / 10
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sizeKey) {
|
if (sizeKey) {
|
||||||
|
Loading…
Reference in New Issue
Block a user