言会咸

言会咸 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

言会咸 提出了问题 · 10月2日

新版qiniu/php-sdk v7.3.0删除资源返回结果与v7.2.10不兼容导致程序出错

新版qiniu/php-sdk v7.3.0删除资源返回结果与v7.2.10不兼容:
$res = $bucketManager->delete($config['bucket'], $file);
v7.3.0版删除资源后返回数组
array(2) { [0] => NULL [1] => NULL }
v7.2.10版删除资源后返回
NULL

1.使用如下判断存在错误
if (!is_null($res) || $res !== null) { return [ 'data'=> '删除qiniu文件失败', 'status'=> false ]; } else { return [ 'data'=> '删除成功', 'status'=> true ]; }

  1. 请问v7.3.0版返回的数组下标0和1分别表示什么?该如何判断是否删除成功,谢谢

关注 1 回答 0

言会咸 提出了问题 · 10月2日

新版qiniu/php-sdk v7.3.0删除资源返回结果与v7.2.10不兼容导致程序出错

新版qiniu/php-sdk v7.3.0删除资源返回结果与v7.2.10不兼容:
$res = $bucketManager->delete($config['bucket'], $file);
v7.3.0版删除资源后返回数组
array(2) { [0] => NULL [1] => NULL }
v7.2.10版删除资源后返回
NULL

1.使用如下判断存在错误
if (!is_null($res) || $res !== null) { return [ 'data'=> '删除qiniu文件失败', 'status'=> false ]; } else { return [ 'data'=> '删除成功', 'status'=> true ]; }

  1. 请问v7.3.0版返回的数组下标0和1分别表示什么?该如何判断是否删除成功,谢谢

关注 1 回答 0

言会咸 关注了问题 · 10月2日

新版qiniu/php-sdk v7.3.0删除资源返回结果与v7.2.10不兼容导致程序出错

新版qiniu/php-sdk v7.3.0删除资源返回结果与v7.2.10不兼容:
$res = $bucketManager->delete($config['bucket'], $file);
v7.3.0版删除资源后返回数组
array(2) { [0] => NULL [1] => NULL }
v7.2.10版删除资源后返回
NULL

1.使用如下判断存在错误
if (!is_null($res) || $res !== null) { return [ 'data'=> '删除qiniu文件失败', 'status'=> false ]; } else { return [ 'data'=> '删除成功', 'status'=> true ]; }

  1. 请问v7.3.0版返回的数组下标0和1分别表示什么?该如何判断是否删除成功,谢谢

关注 1 回答 0

言会咸 赞了回答 · 3月12日

解决两个数组组合

多看看该死的官方文档,这些问题就不用找什么大神来帮忙了... (哎,随手写一波,下面 $result 应该就是你要的 ...)

$result = array_map(function($item1, $item2) {
    return ['id' => $item1, 'oid' => $item2];
}, $id, $oid);

关注 5 回答 5

言会咸 赞了文章 · 2019-08-06

Django Rest Framework 序列化关系模型

这两天一直在学习 Django Rest Framework 这个框架,这是一个非常流行的 REST API 框架,深度整合 Django。但与传统 MVC 模式的不同, Django REST Framework 在使用过程中,需要理解一些新的东西。结合官方 API 分享一下框架中关于序列化关系模型的理解。

序列化模型与序列化关系模型

序列化模型,顾名思义,即对 models 里的数据模型作序列化。而序列化关系模型则是对 models 里数据模型中带有关系的如 ForeignKey, ManyToManyFieldOneToOneField 字段作序列化。Django Rest Framework 提供了灵活的序列化关系模型,让开发者可以自由定制序列化数据模型。

序列化关系模型

根据官方的例子来看一下每一个关系模型的介绍。

数据模型如下:

class Album(models.Model):
    album_name = models.CharField(max_length=100)
    artist = models.CharField(max_length=100)

class Track(models.Model):
    album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
    order = models.IntegerField()
    title = models.CharField(max_length=100)
    duration = models.IntegerField()

    class Meta:
        unique_together = ('album', 'order')
        ordering = ['order']

    def __unicode__(self):
        return '%d: %s' % (self.order, self.title)

StringRelatedField

使用 StringRelatedField 将返回一个对应关系 model 的 __unicode__() 方法的字符串。

这个字段是只读的。

参数:

  • many 如果应用于多对多关系,则应将此参数设置为 True

序列化模型如下

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.StringRelatedField(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

序列化结果如下:

{
    'album_name': 'Things We Lost In The Fire',
    'artist': 'Low',
    'tracks': [
        '1: Sunflower',
        '2: Whitetail',
        '3: Dinosaur Act',
        ...
    ]
}

PrimaryKeyRelatedField

使用 PrimaryKeyRelatedField 将返回一个对应关系 model 的主键。

参数:

  • queryset 用于在验证字段输入时模型实例查找。 关系必须明确设置 queryset,或设置 read_only = True

  • many 如果是对应多个的关系,就设置为 True

  • allow_null 如果设置为 True,则该字段将接受 None 的值或为空的关系的空字符串。默认为 False

  • pk_field 设置为一个字段以控制主键值的序列化/反序列化。例如,pk_field = UUIDField(format ='hex') 将UUID主键序列化为紧凑的十六进制表示。

序列化模型如下

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

序列化结果如下:

{
    'album_name': 'Undun',
    'artist': 'The Roots',
    'tracks': [
        89,
        90,
        91,
        ...
    ]
}

HyperlinkedRelatedField

使用 HyperlinkedRelatedField 将返回一个超链接,该链接指向对应关系 model 的详细数据,view-name 是必选参数,为对应的视图生成超链接。

参数:

  • view_name 用作关系目标的视图名称。如果使用的是标准路由器类,那么它的格式为 <modelname>-detail 的字符串

  • queryset 验证字段输入时用于模型实例查询的查询器。关系必须明确设置 queryset,或设置 read_only = True

  • many 如果应用于多对多关系,则应将此参数设置为 True

  • allow_null 如果设置为 True,则该字段将接受 None 的值或为空的关系的空字符串。默认为 False

  • lookup_field 应该用于查找的目标上的字段。应该对应于引用视图上的 URL 关键字参数。默认值为 pk

  • lookup_url_kwarg 与查找字段对应的 URL conf 中定义的关键字参数的名称。默认使用与 lookup_field 相同的值

  • format 如果使用 format 后缀,超链接字段将对目标使用相同的 format 后缀,除非使用 format 参数进行覆盖。

序列化模型如下

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='track-detail'
    )

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

序列化结果如下:

{
    'album_name': 'Graceland',
    'artist': 'Paul Simon',
    'tracks': [
        'http://www.example.com/api/tracks/45/',
        'http://www.example.com/api/tracks/46/',
        'http://www.example.com/api/tracks/47/',
        ...
    ]
}

SlugRelatedField

使用 SlugRelatedField 将返回一个指定对应关系 model 中的字段,需要擦参数 slug_field 中指定字段名称。

参数:

  • slug_field 应该用于表示目标的字段。这应该是唯一标识任何给定实例的字段。例如 username 。这是必选参数

  • queryset 验证字段输入时用于模型实例查询的查询器。 关系必须明确设置 queryset,或设置 read_only = True

  • many 如果应用于多对多关系,则应将此参数设置为 True

  • allow_null 如果设置为 True,则该字段将接受 None 的值或为空的关系的空字符串。默认为 False

序列化模型如下

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.SlugRelatedField(
        many=True,
        read_only=True,
        slug_field='title'
     )

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

序列化结果如下:

{
    'album_name': 'Dear John',
    'artist': 'Loney Dear',
    'tracks': [
        'Airport Surroundings',
        'Everything Turns to You',
        'I Was Only Going Out',
        ...
    ]
}

HyperlinkedIdentityField

使用 HyperlinkedIdentityField 将返回指定 view-name 的超链接的字段。

参数:

  • view_name 应该用作关系目标的视图名称。如果您使用的是标准路由器类,则它将是格式为 <model_name>-detail 的字符串。必选参数

  • lookup_field 应该用于查找的目标上的字段。应该对应于引用视图上的 URL 关键字参数。默认值为 pk

  • lookup_url_kwarg 与查找字段对应的 URL conf 中定义的关键字参数的名称。默认使用与 lookup_field 相同的值

  • format 如果使用 format 后缀,超链接字段将对目标使用相同的 format 后缀,除非使用 format 参数进行覆盖

序列化模型如下

class AlbumSerializer(serializers.HyperlinkedModelSerializer):
    track_listing = serializers.HyperlinkedIdentityField(view_name='track-list')

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'track_listing')

序列化结果如下:

{
    'album_name': 'The Eraser',
    'artist': 'Thom Yorke',
    'track_listing': 'http://www.example.com/api/track_list/12/',
}

嵌套序列化关系模型

在序列化模型中指定嵌套序列化关系模型将返回一个该嵌套序列化关系模型对应的数据模型中序列化的数据。
读起来有些拗口,看例子吧。

参数:

  • many 如果应用于多对多关系,则应将此参数设置为 True

序列化模型如下

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ('order', 'title', 'duration')

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

序列化结果如下:

 {
    'album_name': 'The Grey Album',
    'artist': 'Danger Mouse',
    'tracks': [
        {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
        {'order': 2, 'title': 'What More Can I Say', 'duration': 264},
        {'order': 3, 'title': 'Encore', 'duration': 159},
    ],
}
查看原文

赞 11 收藏 10 评论 1

言会咸 收藏了文章 · 2019-07-19

【echarts地图制作】下钻到乡镇/街道级别的

需求

展示西安市各区县的地图,点击各区县下钻到各乡镇/街道,只能内网环境使用,不可用通过百度/高德地图来实现。

解决

利用地图数据生成区域的geojson

网络上大部分地图数据只是到省市,最多到区县,再往下的数据就比较难找了;经过搜索,找到了一个可以买地图数据的地方,数据可以精确到乡镇/街道,价格还比较划算;

clipboard.png
地图数据格式为shp(shape格式),如果需要其他的格式,得加点钱获取比如svg、dbf、shx等额外格式的文件;
echarts支持的格式有geojson,此时我们需要一个工具把shp格式的文件转换为geojson格式,有两种工具,推荐第2种:

这个工具是收费,每月最多可以转换3次文件,上传时网站会提示:

Don't forgot to upload all relevant files to your .SHP file - you need at least also .DXF and .SHX files uploaded together with your .SHP file!

不仅要上传shp格式,还要上传dbf和shx等格式的文件,来获得更完整的地理数据,如果把所有格式的数据都上传了,那么生成的geojson可能会有问题(亲测),所以只上传3种格式是比较稳妥的办法;

clipboard.png

上传后会跳转到一个设置的界面,先不要点击开始转换按钮,首先检查一下转换的编码格式,默认为UTF-8,如果是中文的地图数据,最好把转换格式切换为GB18030-Chinese格式;然后点击开始转换就可以了。

clipboard.png

转换超过3个会提示下图,这时可以清一下浏览器缓存试试:

clipboard.png

转换后可以下载到.geojson格式的数据文件,放到项目中时,把.geojson格式手动修改为.json格式,就可以被echarts使用了,直接import geojson格式的文件会报错;

同时上传.dbf .shp .shx .prj格式的文件,然后点击右上角的export,就会看到如下界面,选择geoJSON,就完成了。

clipboard.png

利用geojson展示自定义的echart地图

关于具体如何导入json格式数据到echarts的方法,可以参考官方示例
以下是我自己的代码:

<template>
    <div class="map-chart-wrapper"  ref="myEchart"
        :style="{height:height,width:width, left: mapPosition.left, top: mapPosition.top}">
    </div>
    <!-- '新城区': '&#9312;',
    '碑林区': '&#9313;',
    '莲湖区': '&#9314;', -->
</template>
<script>
import echarts from 'echarts';
import axios from 'axios';
import 'echarts/theme/macarons.js';
import xianshi from '../common/json/xiaan.json'
import zhouzhixian from '../common/json/zhouzhi-cn.json'

const cityMap = {
    '西安市': xianshi,
    '周至县': zhouzhixian,
}
const cityStyleMap = {
    '西安市': {
        position: {
            left: '-112px',
            top: '0px',
        },
        series: {
            left: 0,
            right: 0,
            top: '56px',
            bottom: '55px',
        }
    },
    '周至县':  {
        position: {
            left: '-113px',
            top: '17px',
        },
        series: {
            left: 0,
            right: 0,
            top: '30px',
            bottom: '0px',
        }
    },
}
export default {
    props: {
        width: {
            type: String,
            default: '890px'
        },
        height: {
            type: String,
            default: '517px'
        },
        chartConfig:{
            type: Object,
            default: ()=>({
                title: null,
                backgroundColor: '#6a7985',
                seriesData: [],
                legendData: null,
                xAxisData: null,
                yAxisData: null,
                grid: {}
            }),
        },
        mapData:{
            type: Object,
            default: ()=>({}),
        },

    },
    data() {
        return {
            propsNew: '周至县',
            chart: null,
            mapName: '',
            mapPosition: {
                left: '-117px',
                top: '36px'
            },
            areaGeoMap: {},
            districtList: [
                { label: '周至县', value: '周至县', class: 'zhouzhixian', code: "610124000000"},
                { label: '鄠邑区', value: '鄠邑区', class: 'huxian', code: "610118000000"},
                { label: '长安区', value: '长安区', class: 'changan', code: "610116000000"},
                { label: '雁塔区', value: '雁塔区', class: 'yanta', code: "610113000000"},
                { label: '未央区', value: '未央区', class: 'weiyang', code: "610112000000"},
                { label: '\u2460', value: '新城区', class: 'xincheng', code: "610102000000"},
                { label: '\u2461', value: '碑林区', class: 'beilin', code: "610103000000"},
                { label: '\u2462', value: '莲湖区', class: 'lianhu', code: "610104000000"},
                { label: '灞桥区', value: '灞桥区', class: 'baqiao', code: "610111000000"},
                { label: '高陵区', value: '高陵区', class: 'gaoling', code: "610117000000"},
                { label: '临潼区', value: '临潼区', class: 'lintong', code: "610115000000"},
                { label: '阎良区', value: '阎良区', class: 'yanliang', code: "610114000000"},
                { label: '蓝田县', value: '蓝田县', class: 'lantian', code: "610122000000"},
            ],
        };
    },
    mounted() {
        this.createChart();
        this.registerMap('西安市')
    },
    beforeDestroy() {
        this.destroyChart();
    },
    watch: {
        chartConfig() {
            this.destroyChart();
            this.initChart();
        },
    },
    methods: {
        registerMap(name) { // 注册地图
            axios.get(cityMap[name]).then((response) => {
                const geoJson = response.data
                console.log(geoJson)
                this.areaGeoMap = geoJson.features.reduce((acc, item) => {
                    acc[item.properties.name] = item.properties.cp
                    return acc
                }, {})
                echarts.registerMap(name, geoJson);
                this.mapName = name;
                this.initChart()
            }).catch((error) => {
                alert('地图数据未找到'+ error)
            })
        },
        createChart() {
            this.chart = echarts.init(this.$refs.myEchart, 'macarons');
            window.addEventListener("resize", this.chart.resize);
        },
        initChart() {
            // 清空当前实例,从而清空事件
            this.chart.clear()
            // this.chart.off('click', this.areaClick)
            let titleSubtext = '';
            let mapDown = true;
            if (this.mapName === '西安市') {
                mapDown = false
                titleSubtext = '\u2460' + ' 新城区\n' +
                                '\u2461' +' 碑林区\n' + 
                                '\u2462'+ ' 莲湖区\n';
            }
            let styleData = cityStyleMap[this.mapName]
            this.mapPosition = styleData.position
            let seriesPos = styleData.series
            this.$emit('mapChange', {
                    mapDown,
                    name: this.mapName
                })
            var levelColorMap = {
                '1': 'rgba(241, 109, 115, .8)',
                '2': 'rgba(255, 235, 59, .7)',
                '3': 'rgba(147, 235, 248, 1)'
            };
            var COLORS = ["#070093", "#1c3fbf", "#1482e5", "#70b4eb", "#b4e0f3", "#ffffff"];
            
            // 闪动点的数据
            // const blinkDot = this.areaGeoMap[this.propsNew].concat(100)
            // console.log(blinkDot)
            // 把配置和数据放这里
            const transparentMap = 0
            this.chart.setOption({
                title: {
                    text: '',
                    subtext: titleSubtext,
                    subtextStyle: {
                        color: '#d7d7d7',
                        fontSize: 14,
                        lineHeight: 80,
                        fontFamily: "Microsoft YaHei Light"
                    },
                    left: '320px',
                    top: '65px',
                },
                tooltip: {
                    trigger: 'item',
                    formatter: (data) => {
                        let key = data.name
                        if (key === '\u2460') {
                            key = '新城区'
                        }else if (key === '\u2461') {
                            key = '碑林区'
                        }else if (key === '\u2462') {
                            key = '莲湖区'
                        }
                        return this.mapData[key] || key
                    } 
                },
                series: [
                    {
                        name: '',
                        type: 'map',
                        map: this.mapName,
                        left: seriesPos.left,
                        right: seriesPos.right,
                        top: seriesPos.top,
                        bottom: seriesPos.bottom,
                        selectedMode : 'single',
                        label: {
                            normal: {
                                fontSize: 14,
                                color: '#d7d7d7',
                                show: true,
                                fontFamily: "Microsoft YaHei Light"
                            },
                            emphasis: {
                                show: true
                            }
                        },
                        itemStyle: {
                            normal: {
                                color: function(params){
                                    return levelColorMap[params.value[3]];
                                },
                                // shadowOffsetX:5,
                                // shadowOffsetY:5,
                                // shadowBlur: 5,
                                // shadowColor: 'rgba(255,255,255,0.5)',
                                areaColor: 'rgba(255,255,255,0)',
                                borderColor: new echarts.graphic.RadialGradient(0.3, 0.3, 0.8, [{
                                                offset: 0,
                                                color: 'rgba(13,1,255,0)'
                                            }, {
                                                offset: 1,
                                                color: 'rgba(0,246,255,0)'
                                            }])
                            },
                            emphasis: {
                                areaColor: 'rgba(0,246,255,0.2)',
                                borderWidth: 0,
                                label: {
                                    color: "#fff",
                                }
                            }
                        },
                        data:[
                        
                        ],
                        nameMap: { // unicode 来源: http://xahlee.info/comp/unicode_circled_numbers.html
                            '新城区': '\u2460',
                            '碑林区': '\u2461',
                            '莲湖区': '\u2462',
                        }
                    },
                    {
                        type: 'effectScatter',
                        coordinateSystem: 'geo',
                        // symbol: 'diamond',
                        // showEffectOn: 'render',
                        rippleEffect: {
                            period: 15,
                            scale: 6,
                            brushType: 'fill'
                        },
                        geoIndex: 0,
                        hoverAnimation: true,
                        itemStyle: {
                            normal: {
                                color: 'rgba(56,196,217,1)',
                                shadowBlur: 10,
                                shadowColor: '#fff'
                            }
                        },
                        data: []
                    }
                ]  
            });
            this.chart.on('click', this.areaClick)
        },
        destroyChart() {
            if (this.chart) {
                window.removeEventListener("resize", this.chart.resize);
                this.chart.dispose();
                this.chart = null;
            }
        },
        refreshData(areacode = false) {
            const params = {
                handleBack: (data) => {
                }
            }
            if (areacode) {
                params.area_code = areacode;
            }
            this.$store.dispatch('summaryData', params);
            this.$store.dispatch('rateCredit', params);
        },
        // 地图的某块区域点击, @name参数为地区名称
        areaClick(params) {
            console.log(params)
            const name = params.name
            const selected = params.data.selected
            if (selected) {
                if (name === '周至县') {
                    this.registerMap(name)
                }
                const areaObject = this.districtList.find((area) => {
                    return area.value === name
                })
                if (areaObject) {
                    this.refreshData(areaObject.code)
                }
            }
            else {
                this.refreshData()
            }
        }
    }
}
</script>
<style scoped>
.map-chart-wrapper{
    z-index: 9;
    position: absolute;
}
</style>

结果

设计图的地图效果是3D的,为了达到效果,将地图的颜色设为透明,使用设计图作为背景图,此时需要调整echart地图的比例(top/bottom/right/left),调整好之后,地图选择高亮和点击事件,和地区名字还是继续用echart实现。最终结果:

clipboard.png

参考文章

查看原文

言会咸 赞了文章 · 2019-07-19

【echarts地图制作】下钻到乡镇/街道级别的

需求

展示西安市各区县的地图,点击各区县下钻到各乡镇/街道,只能内网环境使用,不可用通过百度/高德地图来实现。

解决

利用地图数据生成区域的geojson

网络上大部分地图数据只是到省市,最多到区县,再往下的数据就比较难找了;经过搜索,找到了一个可以买地图数据的地方,数据可以精确到乡镇/街道,价格还比较划算;

clipboard.png
地图数据格式为shp(shape格式),如果需要其他的格式,得加点钱获取比如svg、dbf、shx等额外格式的文件;
echarts支持的格式有geojson,此时我们需要一个工具把shp格式的文件转换为geojson格式,有两种工具,推荐第2种:

这个工具是收费,每月最多可以转换3次文件,上传时网站会提示:

Don't forgot to upload all relevant files to your .SHP file - you need at least also .DXF and .SHX files uploaded together with your .SHP file!

不仅要上传shp格式,还要上传dbf和shx等格式的文件,来获得更完整的地理数据,如果把所有格式的数据都上传了,那么生成的geojson可能会有问题(亲测),所以只上传3种格式是比较稳妥的办法;

clipboard.png

上传后会跳转到一个设置的界面,先不要点击开始转换按钮,首先检查一下转换的编码格式,默认为UTF-8,如果是中文的地图数据,最好把转换格式切换为GB18030-Chinese格式;然后点击开始转换就可以了。

clipboard.png

转换超过3个会提示下图,这时可以清一下浏览器缓存试试:

clipboard.png

转换后可以下载到.geojson格式的数据文件,放到项目中时,把.geojson格式手动修改为.json格式,就可以被echarts使用了,直接import geojson格式的文件会报错;

同时上传.dbf .shp .shx .prj格式的文件,然后点击右上角的export,就会看到如下界面,选择geoJSON,就完成了。

clipboard.png

利用geojson展示自定义的echart地图

关于具体如何导入json格式数据到echarts的方法,可以参考官方示例
以下是我自己的代码:

<template>
    <div class="map-chart-wrapper"  ref="myEchart"
        :style="{height:height,width:width, left: mapPosition.left, top: mapPosition.top}">
    </div>
    <!-- '新城区': '&#9312;',
    '碑林区': '&#9313;',
    '莲湖区': '&#9314;', -->
</template>
<script>
import echarts from 'echarts';
import axios from 'axios';
import 'echarts/theme/macarons.js';
import xianshi from '../common/json/xiaan.json'
import zhouzhixian from '../common/json/zhouzhi-cn.json'

const cityMap = {
    '西安市': xianshi,
    '周至县': zhouzhixian,
}
const cityStyleMap = {
    '西安市': {
        position: {
            left: '-112px',
            top: '0px',
        },
        series: {
            left: 0,
            right: 0,
            top: '56px',
            bottom: '55px',
        }
    },
    '周至县':  {
        position: {
            left: '-113px',
            top: '17px',
        },
        series: {
            left: 0,
            right: 0,
            top: '30px',
            bottom: '0px',
        }
    },
}
export default {
    props: {
        width: {
            type: String,
            default: '890px'
        },
        height: {
            type: String,
            default: '517px'
        },
        chartConfig:{
            type: Object,
            default: ()=>({
                title: null,
                backgroundColor: '#6a7985',
                seriesData: [],
                legendData: null,
                xAxisData: null,
                yAxisData: null,
                grid: {}
            }),
        },
        mapData:{
            type: Object,
            default: ()=>({}),
        },

    },
    data() {
        return {
            propsNew: '周至县',
            chart: null,
            mapName: '',
            mapPosition: {
                left: '-117px',
                top: '36px'
            },
            areaGeoMap: {},
            districtList: [
                { label: '周至县', value: '周至县', class: 'zhouzhixian', code: "610124000000"},
                { label: '鄠邑区', value: '鄠邑区', class: 'huxian', code: "610118000000"},
                { label: '长安区', value: '长安区', class: 'changan', code: "610116000000"},
                { label: '雁塔区', value: '雁塔区', class: 'yanta', code: "610113000000"},
                { label: '未央区', value: '未央区', class: 'weiyang', code: "610112000000"},
                { label: '\u2460', value: '新城区', class: 'xincheng', code: "610102000000"},
                { label: '\u2461', value: '碑林区', class: 'beilin', code: "610103000000"},
                { label: '\u2462', value: '莲湖区', class: 'lianhu', code: "610104000000"},
                { label: '灞桥区', value: '灞桥区', class: 'baqiao', code: "610111000000"},
                { label: '高陵区', value: '高陵区', class: 'gaoling', code: "610117000000"},
                { label: '临潼区', value: '临潼区', class: 'lintong', code: "610115000000"},
                { label: '阎良区', value: '阎良区', class: 'yanliang', code: "610114000000"},
                { label: '蓝田县', value: '蓝田县', class: 'lantian', code: "610122000000"},
            ],
        };
    },
    mounted() {
        this.createChart();
        this.registerMap('西安市')
    },
    beforeDestroy() {
        this.destroyChart();
    },
    watch: {
        chartConfig() {
            this.destroyChart();
            this.initChart();
        },
    },
    methods: {
        registerMap(name) { // 注册地图
            axios.get(cityMap[name]).then((response) => {
                const geoJson = response.data
                console.log(geoJson)
                this.areaGeoMap = geoJson.features.reduce((acc, item) => {
                    acc[item.properties.name] = item.properties.cp
                    return acc
                }, {})
                echarts.registerMap(name, geoJson);
                this.mapName = name;
                this.initChart()
            }).catch((error) => {
                alert('地图数据未找到'+ error)
            })
        },
        createChart() {
            this.chart = echarts.init(this.$refs.myEchart, 'macarons');
            window.addEventListener("resize", this.chart.resize);
        },
        initChart() {
            // 清空当前实例,从而清空事件
            this.chart.clear()
            // this.chart.off('click', this.areaClick)
            let titleSubtext = '';
            let mapDown = true;
            if (this.mapName === '西安市') {
                mapDown = false
                titleSubtext = '\u2460' + ' 新城区\n' +
                                '\u2461' +' 碑林区\n' + 
                                '\u2462'+ ' 莲湖区\n';
            }
            let styleData = cityStyleMap[this.mapName]
            this.mapPosition = styleData.position
            let seriesPos = styleData.series
            this.$emit('mapChange', {
                    mapDown,
                    name: this.mapName
                })
            var levelColorMap = {
                '1': 'rgba(241, 109, 115, .8)',
                '2': 'rgba(255, 235, 59, .7)',
                '3': 'rgba(147, 235, 248, 1)'
            };
            var COLORS = ["#070093", "#1c3fbf", "#1482e5", "#70b4eb", "#b4e0f3", "#ffffff"];
            
            // 闪动点的数据
            // const blinkDot = this.areaGeoMap[this.propsNew].concat(100)
            // console.log(blinkDot)
            // 把配置和数据放这里
            const transparentMap = 0
            this.chart.setOption({
                title: {
                    text: '',
                    subtext: titleSubtext,
                    subtextStyle: {
                        color: '#d7d7d7',
                        fontSize: 14,
                        lineHeight: 80,
                        fontFamily: "Microsoft YaHei Light"
                    },
                    left: '320px',
                    top: '65px',
                },
                tooltip: {
                    trigger: 'item',
                    formatter: (data) => {
                        let key = data.name
                        if (key === '\u2460') {
                            key = '新城区'
                        }else if (key === '\u2461') {
                            key = '碑林区'
                        }else if (key === '\u2462') {
                            key = '莲湖区'
                        }
                        return this.mapData[key] || key
                    } 
                },
                series: [
                    {
                        name: '',
                        type: 'map',
                        map: this.mapName,
                        left: seriesPos.left,
                        right: seriesPos.right,
                        top: seriesPos.top,
                        bottom: seriesPos.bottom,
                        selectedMode : 'single',
                        label: {
                            normal: {
                                fontSize: 14,
                                color: '#d7d7d7',
                                show: true,
                                fontFamily: "Microsoft YaHei Light"
                            },
                            emphasis: {
                                show: true
                            }
                        },
                        itemStyle: {
                            normal: {
                                color: function(params){
                                    return levelColorMap[params.value[3]];
                                },
                                // shadowOffsetX:5,
                                // shadowOffsetY:5,
                                // shadowBlur: 5,
                                // shadowColor: 'rgba(255,255,255,0.5)',
                                areaColor: 'rgba(255,255,255,0)',
                                borderColor: new echarts.graphic.RadialGradient(0.3, 0.3, 0.8, [{
                                                offset: 0,
                                                color: 'rgba(13,1,255,0)'
                                            }, {
                                                offset: 1,
                                                color: 'rgba(0,246,255,0)'
                                            }])
                            },
                            emphasis: {
                                areaColor: 'rgba(0,246,255,0.2)',
                                borderWidth: 0,
                                label: {
                                    color: "#fff",
                                }
                            }
                        },
                        data:[
                        
                        ],
                        nameMap: { // unicode 来源: http://xahlee.info/comp/unicode_circled_numbers.html
                            '新城区': '\u2460',
                            '碑林区': '\u2461',
                            '莲湖区': '\u2462',
                        }
                    },
                    {
                        type: 'effectScatter',
                        coordinateSystem: 'geo',
                        // symbol: 'diamond',
                        // showEffectOn: 'render',
                        rippleEffect: {
                            period: 15,
                            scale: 6,
                            brushType: 'fill'
                        },
                        geoIndex: 0,
                        hoverAnimation: true,
                        itemStyle: {
                            normal: {
                                color: 'rgba(56,196,217,1)',
                                shadowBlur: 10,
                                shadowColor: '#fff'
                            }
                        },
                        data: []
                    }
                ]  
            });
            this.chart.on('click', this.areaClick)
        },
        destroyChart() {
            if (this.chart) {
                window.removeEventListener("resize", this.chart.resize);
                this.chart.dispose();
                this.chart = null;
            }
        },
        refreshData(areacode = false) {
            const params = {
                handleBack: (data) => {
                }
            }
            if (areacode) {
                params.area_code = areacode;
            }
            this.$store.dispatch('summaryData', params);
            this.$store.dispatch('rateCredit', params);
        },
        // 地图的某块区域点击, @name参数为地区名称
        areaClick(params) {
            console.log(params)
            const name = params.name
            const selected = params.data.selected
            if (selected) {
                if (name === '周至县') {
                    this.registerMap(name)
                }
                const areaObject = this.districtList.find((area) => {
                    return area.value === name
                })
                if (areaObject) {
                    this.refreshData(areaObject.code)
                }
            }
            else {
                this.refreshData()
            }
        }
    }
}
</script>
<style scoped>
.map-chart-wrapper{
    z-index: 9;
    position: absolute;
}
</style>

结果

设计图的地图效果是3D的,为了达到效果,将地图的颜色设为透明,使用设计图作为背景图,此时需要调整echart地图的比例(top/bottom/right/left),调整好之后,地图选择高亮和点击事件,和地区名字还是继续用echart实现。最终结果:

clipboard.png

参考文章

查看原文

赞 13 收藏 5 评论 21

言会咸 赞了回答 · 2019-06-23

解决根据id数组,删除对象数组中的指定项

楼主,你好!
参考下:

var arr = [1,2];
var allArr = [{id:1,name:"s"},{id:2,name:"ds"},{id:3,name:"gg"}]


// 最终结果
// finalArr = [{id:3,name:"gg"}];

var finalArr = allArr.filter((item) => !arr.includes(item.id));

如有帮助,麻烦点击下采纳,谢谢~

关注 7 回答 6

言会咸 赞了文章 · 2019-06-10

Fetch API

Fetch API

Fetch API 旨在用来简化 HTTP 请求,它包含以下类和方法:

  • fetch 方法:用于发起 HTTP 请求

  • Request 类:用来描述请求

  • Response 类:用来表示响应

  • Headers 类:用来表示 HTTP 头部信息

基本用法

fetch 方法接受一个表示 url 的字符串或者 一个 Request 对象作为参数,返回 Promise 对象。请求成功后将结果封装为 Response 对象。Response 对象上具有 jsontext 等方法,调用这些方法后可以获得不同类型的结果。Response 对象上的这些方法同样返回 Promise 对象。

因此基本的使用方法如下:

// 发起请求
fetch('https://api.github.com/repos/facebook/react').then(function(res){
    // 请求成功,得到 response 对象,调用 response 对象的 json 方法并返回
    return res.json();
}).then(function(data){
    // response 对象的 json 方法执行成功,得到结果
    console.log(data)
});

更多高级用法和配置,详见下面介绍。

fetch 方法

fetch 方法的第一个参数可以是 Request 对象,也可以是一个 url,第二个参数可选,包含一些配置信息。fetch 方法返回 Promise。

Promise fetch(String url [, Object options]);
Promise fetch(Request req [, Object options]);

配置信息包含下列内容:

  • method:请求的方法,如: GET、 POST

  • headers:请求头部信息,可以是一个 Headers 对象的实例,也可以是一个简单对象

  • body: 需要发送的数据,可以是 Blob, BufferSource, FormData, URLSearchParams, 或者 USVString。需要注意的是 GET 和 HEAD 方法不能包含 body。

  • mode:请求的模式,常见取值如下:

    • same-origin:只允许同源的请求,否则直接报错

    • cors:允许跨域,但要求响应中包含 Access-Control-Allow-* 这类表示 CORS 的头部信息,且响应中只有部分头部信息( Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma)可以读取,但响应内容可以不受限地读取。

    • no-cors:允许跨域请求那些响应中没有包含 CORS 头信息的域,但是响应内容是不可读取的。使用使用这种模式配合 ServiceWorkers 可以实现预加载一些资源。

  • credentials:表示是否发送 cookie,有三个可选值 omit, same-origin, include

    • omit:不发生 cookie

    • same-origin: 仅在同源时发生 cookie

    • include:发送 cookie

  • cache:表示处理缓存的策略,可选值为 defaultno-storereloadno-cacheforce-cacheonly-if-cached,关于此可以参考https://fetch.spec.whatwg.org

  • redirect:发生重定向时候的策略。有以下可选值:

    • follow:跟随

    • error:发生错误

    • manual:需要用户手动跟随

  • referrer: 一个字符串,可以是 no-referrer, client, 或者是一个 URL。默认值是 client。

  • integrity:包含一个用于验证子资源完整性的字符串。关于此,可以参看 Subresource Integrity 介绍

该函数返回一个 Promise 对象,若请求成功会用 Response 的实例作为参数调用 resolve ,若请求失败会用一个错误对象来调用 reject。

Headers 类

Headers 类用来表示 HTTP 的头部信息,其构造函数可以接受一个表示 HTTP 头信息的对象,也可以接受一个 Headers 类的实例作为对象:

var header = new Headers({
  'Content-Type': 'image/jpeg',
  'Accept-Charset': 'utf-8'
});

var anotherHeader = new Headers(header);

Headers 实例的方法

append

对一个字段追加信息,如果该字段不存在,就创建一个。

var header = new Headers();
header.append('Accept-Encoding', 'deflate');
header.append('Accept-Encoding', 'gzip');
// Accept-Encoding: ['deflate', 'gzip']

delete

删除某个字段

get

获得某个字段的第一个值

var header = new Headers();
header.append('Accept-Encoding', 'deflate');
header.append('Accept-Encoding', 'gzip');

header.get('Accept-Encoding'); //=> 'deflate'

getAll

获得某个字段所有的值

var header = new Headers();
header.append('Accept-Encoding', 'deflate');
header.append('Accept-Encoding', 'gzip');

header.getAll('Accept-Encoding'); //=> ['deflate', 'gzip']

has

判断是否存在某个字段

set

设置一个字段,如果该字段已经存在,那么会覆盖之前的。

forEach

遍历所有的字段,接受一个回调函数,和可选的第二个参数。可选的第二个参数地值作为回调函数的 this 值。

var header = new Headers();
header.append('Accept-Encoding', 'deflate');

header.forEach(function(value, name, header){
  //...
},this);

Request 类

Request 对象用于描述请求内容。构造函数接受的参数和 fetch 函数的参数形式一样,实际上 fetch 方法会使用传入的参数构造出一个 Request 对象来。

下面例子从 github 抓取到 react 的 star 数并打印出来。

var req = new Request('https://api.github.com/repos/facebook/react',{
  method:'GET'
});

fetch(req).then(function(res){
  return res.json()
}).then(function(data){
  console.log(data.stargazers_count)
});

Request 实例的属性

以下属性均为只读属性。这些属性的意义均在上面介绍 fetch 的参数的时候有过说明。

  • method

  • url

  • headers

  • referrer

  • referrerPolicy:处理来源信息的策略,关于此可以参见Referrer Policy

  • mode

  • credentials

  • redirect

  • integrity

  • cache

Response 类

Response 用来表示 HTTP 请求的响应。其构造函数形式如下:

var res = new Response(body, init);

其中 body 可以是:

  • Blob

  • BufferSource

  • FormData

  • URLSearchParams

  • USVString

init 是一个对象,其中包括以下字段:

  • status:响应的状态码,比如 200,404

  • statusText:状态信息,比如 OK

  • headers: 头部信息,可以是一个对象,也可以是一个 Headers 实例

Response 实例的属性

以下属性均为只读属性

  • bodyUsed:用于表示响应内容是否有被使用过

  • headers:头部信息

  • ok:表明请求是否成功,当响应的状态码是 200~299 时,该值为 true

  • status:状态码

  • statusText:状态信息

  • type:表明了响应的类型,可能是下面几种值:

    • basic: 同源

    • cors:跨域

    • error:出错

    • opaque:Request 的 mode 设置为 no-cors 的时候响应式不透明了,这个时候 type 为 opaque

  • url:响应的地址

Response 实例的方法

  • clone:复制一个响应对象

要想从 Response 的实例中拿到最终的数据需要调用下面这些方法,这些方法都返回一个 Promise 并且使用对应的数据类型来 resolve。

  • arrayBuffer:把响应数据转化为 arrayBuffer 来 resolve

  • blob:把响应数据转换为 Blob 来 resolve

  • formData:把响应数据转化为 formData 来 resolve

  • json:把响应数据解析为对象后 resolve

  • text:把响应数据当做字符串来调用 resolve

总结

最后在把上面使用例子进行一个细致的说明:

// 构造出 Request 对象
var req = new Request('https://api.github.com/repos/facebook/react',{
  method:'GET'
});

// 发起请求,fetch 方法返回一个 Promise 对象
fetch(req).then(function(res){
  // 得到了 response,这里调用 response 的 json 方法
  // 该方法同样返回一个 Promise
  return res.json();
}).then(function(data){
  // 得到解析后的对象
  console.log(data.stargazers_count)
});

可以看出 fetch 方法使用起来比 XMLHttpRequest 要方便的多,关于其兼容性,可以参考 这里,对于不兼容的浏览器,你可以使用 polyfill

查看原文

赞 8 收藏 24 评论 0

言会咸 赞了文章 · 2019-04-20

如何删除 JavaScript 数组中的虚值

翻译:疯狂的技术宅
https://medium.freecodecamp.o...

本文首发微信公众号:前端先锋
欢迎关注,每天都给你推送新鲜的前端技术文章


引用自 MDN:

falsy(虚值)是在 Boolean 上下文中已认定可转换为‘假‘的值.

JavaScript 在需要用到布尔类型值的上下文中使用强制类型转换(Type Conversion )将值转换为布尔值,比如:在条件语句或者循环语句中。

falsy 有时写作 falsey

在 JavaScript 中有很多方法可以从数组中删除元素,但是从数组中删除所有虚值的最简单方法是什么?为了回答这个问题,我们将仔细研究 truthy 与 falsy 值和类型强制转换


算法说明

从数组中删除所有虚值。
JavaScript 中的虚值是 falsenull0""undefinedNaN
提示:尝试将每个值转换为布尔值。
function bouncer(arr) {
  return arr;
}

bouncer([7, "ate", "", false, 9]);

提供的测试用例

  • bouncer([7, "ate", "", false, 9]) 应该返回 [7, "ate", 9]
  • bouncer(["a", "b", "c"]) 应该返回 ["a", "b", "c"]
  • bouncer([false, null, 0, NaN, undefined, ""]) 应该返回 []
  • bouncer([1, null, NaN, 2, undefined]) 应该返回 [1, 2]

解决方案:.filter( ) 和 Boolean( )

理解问题:我们有一个作为输入的数组。目标是从数组中删除所有的虚值然后将其返回。

freeCodeCamp 上的好心人告诉我们,JavaScript 中的虚值是 falsenull0""undefinedNaN

他们也给了我们一个重要的提示!他们建议将数组的每个值转换为布尔值以完成此挑战。我认为这个提示很不错!

示例/测试用例:前面提供的测试用例告诉我们,如果输入数组只包含虚值,那么应该只返回一个空数组。这非常简单。

数据结构:在这里我们将坚持使用数组。

我们来谈谈.filter()

.filter()创建一个新数组,其中包含通过所提供函数测试的所有元素。

换句话说,.filter() 遍历数组中的每个元素并保留通过其中某个测试的所有元素。数组中未通过该测试的所有元素都被过滤掉了 —— 被删除了。

如果我们有一个数组并且只想保留大于 100 的数字,可以用 .filter() 来实现:

let numbers = [4, 56, 78, 99, 101, 150, 299, 300]
numbers.filter(number => number > 100)
// returns [ 101, 150, 299, 300 ]

我们再来谈谈那个将每个元素转换为布尔值的提示。这是一个很好的提示,因为我们可以用 .filter() 返回只有真值(truthy)的数组。

我们将通过JavaScript类型转换来实现这一目标。

JavaScript 为我们提供了将一种数据类型转换为另一种的有用函数, String()转换为字符串,Number() 转换为数字,Boolean() 转换为布尔值。

例如:

String(1234)
// returns "1234"
Number("47")
// returns 47
Boolean("meow")
// returns true

Boolean() 是我们完成这个挑战所需要的函数。如果提供给 Boolean() 的参数是真值,那么 Boolean() 将返回 true 。如果提供给 Boolean() 的参数是虚值,那么 Boolean() 将返回 false

这对我们非常有用,因为我们从指令中知道只有 falsenull0""undefinedNaN 在 JavaScript 中是虚值。其他每一个值都是真值。知道如果我们将输入数组中的每个值都转换为布尔值,就可以删除所有值为 false 的元素,这就满足了此挑战的要求。

算法

  1. 确定 arr 中的哪些值是虚值。
  2. 删除所有虚值。
  3. 返回仅包含真值(truthy)的新数组。

代码

function bouncer(arr) {
  // Use filter to remove falsy elements from arr.
  let onlyTruthyValues = arr.filter(element => Boolean(element) === true)
  //                                7          Boolean(7) is true
  //                                "ate"      Boolean("ate") is true
  //                                ""         Boolean("") is false
  //                                false      Boolean(false) is false
  //                                9          Boolean(9) is true

  // Return the new array.
  return onlyTruthyValues
  //     [7, "ate", 9]
}

bouncer([7, "ate", "", false, 9]);

去掉注释并删除局部变量:

function bouncer(arr) {
  return arr.filter(element => Boolean(element) === true)
}

bouncer([7, "ate", "", false, 9]);

如果你有其他解决方案或建议,请在评论中分享!


本文是该系列 freeCodeCamp Algorithm Scripting 的一部分。
本文引用了 freeCodeCamp Basic Algorithm Scripting:Falsy Bouncer

本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章


欢迎继续阅读本专栏其它高赞文章:

查看原文

赞 14 收藏 12 评论 2

认证与成就

  • 获得 0 次点赞
  • 获得 2 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 2 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2019-03-10
个人主页被 71 人浏览