Commit 7e7c73ce9784981320c9b51f4bbd6150571f019f

Authored by 徐烜
1 parent e20cc903

闵行公交电子站牌页面组件化

1、新建mggj/chart目录,添加mhgj-eBusStop-line-chart组件
front-end/h5/src/components/core/plugins/bsth/lggj/list/models/eBusStop-line-chart-list-scrollPage-innerData.js
... ... @@ -159,7 +159,6 @@ class EBusStopLineChartListScrollPageInnerData {
159 159 }
160 160  
161 161 scrollListComponent.scrollTimer.count++
162   -
163 162 } else {
164 163 scrollListComponent.$emit('scrollTop', currentViewTop)
165 164 }
... ...
front-end/h5/src/components/core/plugins/bsth/mhgj/chart/css/mhgj-eBusStop-line-chart.css 0 → 100644
  1 +/*
  2 + 内部使用的是border-box
  3 + 注意:
  4 + 1、这个设置很重要,因为内部计算width是减去两侧border的
  5 + 2、在编辑器模式下,外层的.ant-layout会给内层所有元素设置border-box,此时你不设置无所谓
  6 + 3、但是在打包预览模式下,是没有外层.ant-layout定义的,此时如果组件内部不定义,则会使用content-box,会和内部计算宽度产生偏差
  7 +*/
  8 +.mhgj-eBusStop-line-chart-outer-div, .mhgj-eBusStop-line-chart-outer-div * {
  9 + box-sizing: border-box;
  10 +}
  11 +
  12 +/**
  13 + 电子站牌线路模拟图使用的css
  14 + */
  15 +svg.mhgj-eBusStop-line-chart {
  16 + width: 100%;
  17 + height: 100%;
  18 + position: absolute;
  19 + left: 0;
  20 +
  21 + /* 文本css */
  22 + font-style: normal;
  23 + font-variant-ligatures: normal;
  24 + font-variant-caps: normal;
  25 + font-variant-numeric: normal;
  26 + font-variant-east-asian: normal;
  27 + font-weight: 400;
  28 + font-stretch: normal;
  29 + font-size: 14px;
  30 + line-height: 20px;
  31 + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
  32 +}
  33 +
  34 +svg.mhgj-eBusStop-line-chart g.part {
  35 +}
  36 +svg.mhgj-eBusStop-line-chart g.part rect.main {
  37 + fill: #ffffff;
  38 + stroke: rgb(0, 0, 0);
  39 + stroke-width: 1;
  40 + Pointer-events: none;
  41 +}
  42 +svg.mhgj-eBusStop-line-chart g.part rect.titleBackground {
  43 + fill: #7dc6fe;
  44 + stroke-width: 0;
  45 + Pointer-events: none;
  46 +}
  47 +svg.mhgj-eBusStop-line-chart g.part g.titleBound {
  48 +}
  49 +svg.mhgj-eBusStop-line-chart g.part g.titleBound image.CarIcon {
  50 + /** 第一个part内部会使用 */
  51 +}
  52 +svg.mhgj-eBusStop-line-chart g.part g.titleBound text.title {
  53 + font-size: 60px;
  54 + font-weight: 900;
  55 + letter-spacing: -.2px;
  56 + text-shadow: 0 0 2px #dadada;
  57 + Pointer-events: none;
  58 +}
  59 +
  60 +/** 每个part的下半部分差异较大,分开css */
  61 +/** part1用 */
  62 +svg.mhgj-eBusStop-line-chart g.part g.content1Bound {
  63 +}
  64 +svg.mhgj-eBusStop-line-chart g.part g.content1Bound text.content1 {
  65 + font-size: 28px;
  66 + font-weight: 500;
  67 + letter-spacing: -.2px;
  68 + text-shadow: 0 0 2px #dadada;
  69 + Pointer-events: none;
  70 +}
  71 +svg.mhgj-eBusStop-line-chart g.part g.content1Bound {
  72 +}
  73 +svg.mhgj-eBusStop-line-chart g.part g.content2Bound text.content2 {
  74 + font-size: 28px;
  75 + font-weight: 500;
  76 + letter-spacing: -.2px;
  77 + text-shadow: 0 0 2px #dadada;
  78 + Pointer-events: none;
  79 +}
  80 +/** part2用 */
  81 +svg.mhgj-eBusStop-line-chart g.part path.bound {
  82 + stroke: rgb(0, 0, 0);
  83 + stroke-width: 1;
  84 + stroke-dasharray: 4,2;
  85 +}
  86 +svg.mhgj-eBusStop-line-chart g.part g.content3Bound {
  87 +}
  88 +svg.mhgj-eBusStop-line-chart g.part g.content3Bound text.content3 {
  89 + font-size: 28px;
  90 + font-weight: 600;
  91 + letter-spacing: -.2px;
  92 + text-shadow: 0 0 2px #dadada;
  93 + Pointer-events: none;
  94 +}
  95 +svg.mhgj-eBusStop-line-chart g.part g.content4Bound {
  96 +}
  97 +svg.mhgj-eBusStop-line-chart g.part g.content4Bound text.content4 {
  98 + font-size: 28px;
  99 + font-weight: 600;
  100 + letter-spacing: -.2px;
  101 + text-shadow: 0 0 2px #dadada;
  102 + Pointer-events: none;
  103 +}
  104 +svg.mhgj-eBusStop-line-chart g.part g.content5Bound {
  105 +}
  106 +svg.mhgj-eBusStop-line-chart g.part g.content5Bound text.content5_left {
  107 + font-size: 80px;
  108 + font-weight: bold;
  109 + fill: #cd2a40;
  110 + letter-spacing: -.2px;
  111 + text-shadow: 0 0 2px #dadada;
  112 + Pointer-events: none;
  113 +}
  114 +svg.mhgj-eBusStop-line-chart g.part g.content5Bound text.content5_right {
  115 + font-size: 20px;
  116 + letter-spacing: -.2px;
  117 + text-shadow: 0 0 2px #dadada;
  118 + Pointer-events: none;
  119 +}
  120 +
  121 +svg.mhgj-eBusStop-line-chart g.part g.content6Bound {
  122 +}
  123 +svg.mhgj-eBusStop-line-chart g.part g.content6Bound text.content6_left {
  124 + font-size: 80px;
  125 + font-weight: bold;
  126 + fill: #cd2a40;
  127 + letter-spacing: -.2px;
  128 + text-shadow: 0 0 2px #dadada;
  129 + Pointer-events: none;
  130 +}
  131 +svg.mhgj-eBusStop-line-chart g.part g.content6Bound text.content6_right {
  132 + font-size: 20px;
  133 + letter-spacing: -.2px;
  134 + text-shadow: 0 0 2px #dadada;
  135 + Pointer-events: none;
  136 +}
  137 +
  138 +/** part3用 */
  139 +svg.mhgj-eBusStop-line-chart g.part g.contentAllBound {
  140 +}
  141 +svg.mhgj-eBusStop-line-chart g.part g.contentAllBound text.content {
  142 + font-size: 28px;
  143 + font-weight: 600;
  144 + letter-spacing: -.2px;
  145 + text-shadow: 0 0 2px #dadada;
  146 + Pointer-events: none;
  147 +}
  148 +svg.mhgj-eBusStop-line-chart g.part g.contentAllBound text.arrivalTime {
  149 + font-size: 80px;
  150 + font-weight: 600;
  151 + letter-spacing: -.2px;
  152 + text-shadow: 0 0 2px #dadada;
  153 + Pointer-events: none;
  154 +}
... ...
front-end/h5/src/components/core/plugins/bsth/mhgj/chart/mhgj-eBusStop-line-chart.js 0 → 100644
  1 +/**
  2 + * 自定义线路模拟图组件(闵行公交电子站牌使用)
  3 + */
  4 +import moment from 'moment'
  5 +
  6 +import PropTypes from '@luban-h5/plugin-common-props'
  7 +
  8 +import './css/mhgj-eBusStop-line-chart.css'
  9 +import CarIcon from './svgicon/car.svg'
  10 +
  11 +import Utils from 'core/plugins/bsth/bsth-utils'
  12 +import { MhgjEBusStopLineChartData } from 'core/plugins/bsth/mhgj/chart/models/MhgjEBusStopLineChartData'
  13 +
  14 +export default {
  15 + extra: {
  16 + defaultStyle: { // 默认属性
  17 + top: 0,
  18 + left: 0,
  19 + width: 1000,
  20 + height: 242
  21 + }
  22 + },
  23 + name: 'mhgj-eBusStop-line-chart',
  24 + data () {
  25 + this.private_svgns = 'http://www.w3.org/2000/svg' // svg元素名字空间
  26 + this.private_svg = null // 创建的根svg元素,由mounted钩子函数创建
  27 + // eslint-disable-next-line
  28 + this.private_jQuery = jQuery.noConflict() // jquery引用
  29 + // eslint-disable-next-line
  30 + this.private_d3 = d3 // d3引用
  31 +
  32 + return {
  33 + /**
  34 + * 监控外层元素的宽度高度变化
  35 + * 1、由于编辑器缩放,自定义组件无法监控,所以需要定义一个定时器监控最外层元素的大小变化
  36 + * 2、建议所有自定义组件,最外层都定义一个div包在自定义组件最外层,不要关联任何自定义的属性,样式对应编辑器的通用样式
  37 + */
  38 + watchWidthHeightTimer: {
  39 + timer: null,
  40 + count: 0,
  41 + millisecond: 1000
  42 + },
  43 +
  44 + // TODO:其他timer
  45 +
  46 + // 注意:css里设定了box-sizing: border-box;,所以组件本身的宽高包括了margin,padding,border
  47 + // 所以计算内部其他组件宽高需要减去margin,padding,border
  48 + component_width: 350, // 组件宽度
  49 + component_height: 400, // 组件高度
  50 +
  51 + svg_width: 350, // svg根元素的宽度
  52 + svg_height: 400, // svg根元素的高度
  53 +
  54 + // TODO:其他属性
  55 +
  56 + eBusStopData: null // 电子站牌数据(MhgjEBusStopLineChartData类型)
  57 + }
  58 + },
  59 + computed: {
  60 + // TODO:其他计算属性
  61 + },
  62 + props: {
  63 + //------------------- 内部不可编辑属性 -----------------------//
  64 + useMode: PropTypes.string({ // 自定义使用模式,alone:(单独使用),child:(子组件)
  65 + defaultValue: 'alone',
  66 + label: '使用模式',
  67 + visible: false
  68 + }),
  69 + editorMode: PropTypes.string({ // 编辑模式会由编辑器自动注入(值:edit, preview)
  70 + defaultValue: 'edit',
  71 + label: '模式',
  72 + visible: false
  73 + }),
  74 + line_chart_outer_div_width: PropTypes.number({
  75 + defaultValue: 350,
  76 + label: 'mhgj-eBusStop-line-chart-outer-div样式的div宽度',
  77 + visible: false
  78 + }),
  79 + line_chart_outer_div_height: PropTypes.number({
  80 + defaultValue: 300,
  81 + label: 'mhgj-eBusStop-line-chart-outer-div样式的div高度',
  82 + visible: false
  83 + }),
  84 + eBusStopData_child: { // 作为子组件,父对象传值
  85 + type: MhgjEBusStopLineChartData,
  86 + default: function () {
  87 + return null
  88 + }
  89 + },
  90 +
  91 + //---------------------- 外部编辑器可编辑属性 -----------------------//
  92 + // 数据属性
  93 + _flag_1_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="数据属性" class="bsth-line-item-divider"></hr>) } }),
  94 + // 图外层css
  95 + _flag_2_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图外层css属性" class="bsth-line-item-divider"></hr>) } }),
  96 + margin_left: PropTypes.number({ label: '图左边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  97 + margin_right: PropTypes.number({ label: '图右边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  98 + margin_top: PropTypes.number({ label: '图上边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  99 + margin_bottom: PropTypes.number({ label: '图底部margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  100 + border_size: PropTypes.number({ label: '图边框宽度', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  101 + background_color: PropTypes.color({ label: '背景颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  102 + // 图内层css
  103 + _flat_2_1_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层svg css属性" class="bsth-line-item-divider"></hr>) } }),
  104 + svg_background: PropTypes.color({ label: '整体svg背景颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  105 + _flag_3_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层线路信息css属性" class="bsth-line-item-divider"></hr>) } }),
  106 + part1_background_color: PropTypes.color({ label: '背景颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  107 + part1_border_size: PropTypes.number({ label: '图边框宽度', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  108 + part1_line_name_font_size: PropTypes.number({ label: '线路名称字体大小', defaultValue: 60, layout: { prefixCls: 'bsth-line' } }),
  109 + part1_line_name_font_color: PropTypes.color({ label: '线路名称字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } }),
  110 + part1_terminal_stop_font_size: PropTypes.number({ label: '开往站点字体大小', defaultValue: 28, layout: { prefixCls: 'bsth-line' } }),
  111 + part1_terminal_stop_font_color: PropTypes.color({ label: '开往站点字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } }),
  112 + _flag_4_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层本班车信息css属性" class="bsth-line-item-divider"></hr>) } }),
  113 + part2_background_color: PropTypes.color({ label: '背景颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  114 + part2_border_size: PropTypes.number({ label: '图边框宽度', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  115 + part2_title1_font_size: PropTypes.number({ label: '标题1字体大小', defaultValue: 30, layout: { prefixCls: 'bsth-line' } }),
  116 + part2_title1_font_color: PropTypes.color({ label: '标题1字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } }),
  117 + part2_title1_background_color: PropTypes.color({ label: '标题1背景颜色', defaultValue: '#acd48e', layout: { prefixCls: 'bsth-line' } }),
  118 + part2_title2_font_size: PropTypes.number({ label: '标题2字体大小', defaultValue: 28, layout: { prefixCls: 'bsth-line' } }),
  119 + part2_title2_font_color: PropTypes.color({ label: '标题2字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } }),
  120 + part2_title2_background_color: PropTypes.color({ label: '标题2背景颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  121 + part2_arrival_time_font_size: PropTypes.number({ label: '到达时间字体大小', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  122 + part2_arrival_time_font_color: PropTypes.color({ label: '到达时间字体颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  123 + part2_arrival_time_minutes_left_font_size: PropTypes.number({ label: '到达时间(分钟)左边字体大小', defaultValue: 80, layout: { prefixCls: 'bsth-line' } }),
  124 + part2_arrival_time_minutes_left_font_color: PropTypes.color({ label: '到达时间(分钟)左边字体颜色', defaultValue: '#cd2a40', layout: { prefixCls: 'bsth-line' } }),
  125 + part2_arrival_time_minutes_right_font_size: PropTypes.number({ label: '到达时间(分钟)右边字体大小', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  126 + part2_arrival_time_minutes_right_font_color: PropTypes.color({ label: '到达时间(分钟)右边字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } }),
  127 + part2_from_stops_left_font_size: PropTypes.number({ label: '距离本站(几站)左边字体大小', defaultValue: 80, layout: { prefixCls: 'bsth-line' } }),
  128 + part2_from_stops_left_font_color: PropTypes.color({ label: '距离本站(几站)左边字体颜色', defaultValue: '#cd2a40', layout: { prefixCls: 'bsth-line' } }),
  129 + part2_from_stops_right_font_size: PropTypes.number({ label: '距离本站(几站)右边字体大小', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  130 + part2_from_stops_right_font_color: PropTypes.color({ label: '距离本站(几站)右边字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } }),
  131 + _flag_5_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层下一班车信息css属性" class="bsth-line-item-divider"></hr>) } }),
  132 + part3_background_color: PropTypes.color({ label: '背景颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  133 + part3_border_size: PropTypes.number({ label: '图边框宽度', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  134 + part3_title1_font_size: PropTypes.number({ label: '标题1字体大小', defaultValue: 30, layout: { prefixCls: 'bsth-line' } }),
  135 + part3_title1_font_color: PropTypes.color({ label: '标题1字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } }),
  136 + part3_title1_background_color: PropTypes.color({ label: '标题1背景颜色', defaultValue: '#7dc6fe', layout: { prefixCls: 'bsth-line' } }),
  137 + part3_title2_font_size: PropTypes.number({ label: '标题2字体大小', defaultValue: 28, layout: { prefixCls: 'bsth-line' } }),
  138 + part3_title2_font_color: PropTypes.color({ label: '标题2字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } }),
  139 + part3_title2_background_color: PropTypes.color({ label: '标题2背景颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  140 + part3_arrival_time_font_size: PropTypes.number({ label: '到达时间字体大小', defaultValue: 80, layout: { prefixCls: 'bsth-line' } }),
  141 + part3_arrival_time_font_color: PropTypes.color({ label: '到达时间字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } })
  142 +
  143 + },
  144 + render () {
  145 + const innerDivStyle = {
  146 + 'width': this.component_width + 'px',
  147 + 'height': this.component_height + 'px',
  148 + 'border': this.border_size + 'px solid black',
  149 + 'margin-left': this.margin_left + 'px',
  150 + 'margin-right': this.margin_right + 'px',
  151 + 'margin-top': this.margin_top + 'px',
  152 + 'margin-bottom': this.margin_bottom + 'px',
  153 + 'background': this.background_color,
  154 + 'position': 'relative'
  155 + }
  156 + const svgStyle = {
  157 + 'width': this.svg_width + 'px',
  158 + 'height': this.svg_height + 'px',
  159 + 'background-color': this.svg_background
  160 + }
  161 +
  162 + // TODO:其他元素
  163 +
  164 + /* 最外层div对应编辑器的通用样式 */
  165 + return (
  166 + <div class="mhgj-eBusStop-line-chart-outer-div">
  167 + <div style={innerDivStyle}>
  168 + <svg class="mhgj-eBusStop-line-chart"
  169 + style={svgStyle}>
  170 + </svg>
  171 + </div>
  172 + </div>
  173 + )
  174 + },
  175 + beforeMount () {
  176 + // 设置数据
  177 + if (this.useMode === 'alone') { // 单独使用,使用测试数据
  178 + this.eBusStopData = MhgjEBusStopLineChartData.generateTestData_type1()
  179 + // this.eBusStopData = MhgjEBusStopLineChartData.generateTestData_type2()
  180 + // this.eBusStopData = MhgjEBusStopLineChartData.generateTestData_type3()
  181 + } else { // 自组件使用,使用父组件传值
  182 + this.eBusStopData = this.eBusStopData_child
  183 + }
  184 + },
  185 + mounted () {
  186 + // svg元素
  187 + this.private_svg = this.findD3SvgDom()
  188 + // this.private_up_rect_wrap_svg = this.findD3UpRectWrapSvg()
  189 +
  190 + // 使用外部元素的框架定义图的长宽
  191 + let $jQuery = this.private_jQuery
  192 + this.component_width = $jQuery(this.$el).width() - this.margin_left - this.margin_right
  193 + this.component_height = $jQuery(this.$el).height() - this.margin_top - this.margin_bottom
  194 +
  195 + if (this.useMode === 'child') {
  196 + this.component_width = this.line_chart_outer_div_width - this.margin_left - this.margin_right
  197 + this.component_height = this.line_chart_outer_div_height - this.margin_top - this.margin_bottom
  198 + }
  199 +
  200 + // 开启外部元素长宽监控计数
  201 + /**
  202 + * 开启外部元素长宽监控逻辑(class='line-chart-outer-div')
  203 + * 1、使用模式是alone,并且是编辑模式edit
  204 + * 2、preview预览模式下有条件监控
  205 + */
  206 + if (this.useMode === 'alone' && this.editorMode === 'edit') {
  207 + this.watchWidthHeightTimer.count++
  208 + }
  209 +
  210 + // 刷新svg
  211 + this.refreshSvg()
  212 + },
  213 + destroyed () {
  214 + // 组件删除的时候,删除监控定时器
  215 + let timer = this.watchWidthHeightTimer.timer
  216 + if (timer) {
  217 + clearTimeout(timer)
  218 + this.watchWidthHeightTimer.timer = null
  219 + }
  220 +
  221 + // TODO:其他定时器
  222 + },
  223 + watch: {
  224 + //------------ 定时器监控 -----------//
  225 + 'watchWidthHeightTimer.count' () { // 定时器监控
  226 + let timer = this.watchWidthHeightTimer.timer
  227 + if (timer) {
  228 + clearTimeout(timer)
  229 + this.watchWidthHeightTimer.timer = null
  230 + }
  231 +
  232 + let self = this
  233 + let $jQuery = this.private_jQuery
  234 + self.watchWidthHeightTimer.timer = setTimeout(function () {
  235 + // 处理逻辑
  236 + let width = $jQuery(self.$el).width()
  237 + let height = $jQuery(self.$el).height()
  238 +
  239 + if (width !== self.component_width) {
  240 + self.component_width = width - self.margin_left - self.margin_right
  241 + }
  242 + if (height !== self.component_height) {
  243 + self.component_height = height - self.margin_top - self.margin_bottom
  244 + }
  245 + self.watchWidthHeightTimer.count++
  246 + }, self.watchWidthHeightTimer.millisecond)
  247 + },
  248 + // TODO:其他定时器监控
  249 +
  250 + //-------------- 不可编辑属性监控 ---------------//
  251 + /**
  252 + * 当组件作为子组件使用时(useMode=child),line-chart-outer-div样式的div尺寸无法通过编辑器改变(通用样式)
  253 + * 必须由父组件设定,自组件需要监控改变
  254 + */
  255 + line_chart_outer_div_width: function (val) {
  256 + let self = this
  257 + if (self.useMode === 'child') {
  258 + self.component_width = val - self.margin_left - self.margin_right
  259 + }
  260 + },
  261 + line_chart_outer_div_height: function (val) {
  262 + let self = this
  263 + if (self.useMode === 'child') {
  264 + self.component_height = val - self.margin_top - self.margin_bottom
  265 + }
  266 + },
  267 + eBusStopData_child: function (val) {
  268 + let self = this
  269 + if (self.useMode === 'child') {
  270 + self.eBusStopData_child = val
  271 + }
  272 + },
  273 +
  274 + //------------- data方法中绑定的数据监控 --------------------//
  275 + // ----------- 数据属性 ----------- //
  276 + eBusStopData: function (currentVal, oldVal) {
  277 + let self = this
  278 + if (!Utils.objectEquals(currentVal, oldVal)) {
  279 + self.refreshSvg()
  280 + }
  281 + },
  282 + // ------------ 本身宽高 ----------- //
  283 + component_width () {
  284 + let self = this
  285 + self.svg_width = self.component_width - self.border_size * 2
  286 + },
  287 + component_height () {
  288 + let self = this
  289 + self.svg_height = self.component_height - self.border_size * 2
  290 + },
  291 +
  292 + svg_width () {
  293 + let self = this
  294 + self.refreshSvg()
  295 + },
  296 + svg_height () {
  297 + let self = this
  298 + self.refreshSvg()
  299 + },
  300 +
  301 + // TODO:其他绑定属性
  302 +
  303 + //--------------- 外部编辑器可编辑属性监控 -----------------//
  304 + //--------- 图外层css监控 -------//
  305 + margin_left () {
  306 + let self = this
  307 + self.component_width = self.component_width - self.margin_left - self.margin_right
  308 + },
  309 + margin_right () {
  310 + let self = this
  311 + self.component_width = self.component_width - self.margin_left - self.margin_right
  312 + },
  313 + margin_top () {
  314 + let self = this
  315 + self.component_height = self.component_height - self.margin_top - self.margin_bottom
  316 + },
  317 + margin_bottom () {
  318 + let self = this
  319 + self.component_height = self.component_height - self.margin_top - self.margin_bottom
  320 + },
  321 + border_size () {
  322 + let self = this
  323 + self.svg_width = self.component_width - self.border_size * 2
  324 + self.svg_height = self.component_height - self.border_size * 2
  325 + },
  326 +
  327 + //---------- 图内层css监控 --------//
  328 + // part1 线路信息,对应_flag_3_属性集合
  329 + part1_background_color () {
  330 + let self = this;
  331 + // TODO:
  332 + },
  333 + part1_border_size () {
  334 + let self = this;
  335 + // TODO:
  336 + },
  337 + part1_line_name_font_size () {
  338 + let self = this;
  339 + // TODO:
  340 + },
  341 + part1_line_name_font_color () {
  342 + let self = this;
  343 + // TODO:
  344 + },
  345 + part1_terminal_stop_font_size () {
  346 + let self = this;
  347 + // TODO:
  348 + },
  349 + part1_terminal_stop_font_color () {
  350 + let self = this;
  351 + // TODO:
  352 + },
  353 +
  354 + // part2 本班车信息,对应_flag_4属性集合
  355 + part2_background_color () {
  356 + // TODO:
  357 + },
  358 + part2_border_size () {
  359 + // TODO:
  360 + },
  361 + part2_title1_font_size () {
  362 + // TODO:
  363 + },
  364 + part2_title1_font_color () {
  365 + // TODO:
  366 + },
  367 + part2_title1_background_color () {
  368 + // TODO:
  369 + },
  370 + part2_title2_font_size () {
  371 + // TODO:
  372 + },
  373 + part2_title2_font_color () {
  374 + // TODO:
  375 + },
  376 + part2_title2_background_color () {
  377 + // TODO:
  378 + },
  379 + part2_arrival_time_font_size () {
  380 + // TODO:
  381 + },
  382 + part2_arrival_time_font_color () {
  383 + // TODO:
  384 + },
  385 + part2_arrival_time_minutes_left_font_size () {
  386 + // TODO:
  387 + },
  388 + part2_arrival_time_minutes_left_font_color () {
  389 + // TODO:
  390 + },
  391 + part2_arrival_time_minutes_right_font_size () {
  392 + // TODO:
  393 + },
  394 + part2_arrival_time_minutes_right_font_color () {
  395 + // TODO:
  396 + },
  397 + part2_from_stops_left_font_size () {
  398 + // TODO:
  399 + },
  400 + part2_from_stops_left_font_color () {
  401 + // TODO:
  402 + },
  403 + part2_from_stops_right_font_size () {
  404 + // TODO:
  405 + },
  406 + part2_from_stops_right_font_color () {
  407 + // TODO:
  408 + },
  409 +
  410 + // part3 下一班车信息,对应_flag_5_属性集合
  411 + part3_background_color () {
  412 + // TODO:
  413 + },
  414 + part3_border_size () {
  415 + // TODO:
  416 + },
  417 + part3_title1_font_size () {
  418 + // TODO:
  419 + },
  420 + part3_title1_font_color () {
  421 + // TODO:
  422 + },
  423 + part3_title1_background_color () {
  424 + // TODO:
  425 + },
  426 + part3_title2_font_size () {
  427 + // TODO:
  428 + },
  429 + part3_title2_font_color () {
  430 + // TODO:
  431 + },
  432 + part3_title2_background_color () {
  433 + // TODO:
  434 + },
  435 + part3_arrival_time_font_size () {
  436 + // TODO:
  437 + },
  438 + part3_arrival_time_font_color () {
  439 + // TODO:
  440 + }
  441 +
  442 + },
  443 + methods: {
  444 + findD3SvgDom () {
  445 + let $jQuery = this.private_jQuery
  446 + let d3 = this.private_d3
  447 + let svgDom = $jQuery(this.$el).find('svg')[0]
  448 + return d3.select(svgDom)
  449 + },
  450 +
  451 + // 刷新svg数据,对应_flag_3_,_flag_4_,_flag_5_属性集合
  452 + refreshSvg () {
  453 + let self = this
  454 +
  455 + let d3 = self.private_d3
  456 + let svg = self.private_svg
  457 + let width = self.svg_width
  458 + let height = self.svg_height
  459 + let partUpPadding = 10
  460 + let partDownPadding = 10
  461 + let partLeftPadding = 10
  462 + let partRightPadding = 10
  463 + let partBetweenPadding = 5
  464 +
  465 + let svgData = self.eBusStopData.generateSvgData()
  466 + let showType = self.eBusStopData.showType
  467 +
  468 + // ------------ 0、前置计算准备 --------------//
  469 + // 创建x轴比例尺
  470 + let xScale = d3.scaleLinear()
  471 + .domain([0, 3]) // 定义域
  472 + .range([partLeftPadding, width - partRightPadding]) // 值域
  473 + let yScale = d3.scaleLinear()
  474 + .domain([0, 1]) // 定义域
  475 + .range([partUpPadding, height - partDownPadding]) // 值域
  476 + // 计算三个part的宽度(宽度相同)
  477 + let partWidth = Math.floor((width - partLeftPadding - partRightPadding - partBetweenPadding * 2) / 3)
  478 + let partHeight = height - partUpPadding - partDownPadding
  479 +
  480 + // ------------ 1、添加g元素 ----------------//
  481 + let itemsUpdate = svg.selectAll('g.part')
  482 + .data(svgData, function (d) {
  483 + return d.text1
  484 + })
  485 + let itemsEnter = itemsUpdate
  486 + let itemsExit = itemsUpdate.exit()
  487 +
  488 + itemsExit.remove()
  489 + itemsEnter = itemsEnter.enter().append('g')
  490 + .classed('part', true)
  491 + .attr('transform', function (d, i) {
  492 + let x, y
  493 + if (i === 0) { // part1
  494 + x = xScale(0)
  495 + } else if (i === 1) { // part2
  496 + x = xScale(0) + partWidth + partBetweenPadding
  497 + } else if (i === 2) { // part3
  498 + x = xScale(0) + partWidth * 2 + partBetweenPadding * 2
  499 + }
  500 + y = yScale(0)
  501 + return `translate(${x}, ${y})`
  502 + })
  503 + itemsUpdate
  504 + .attr('transform', function (d, i) {
  505 + let x, y
  506 + if (i === 0) { // part1
  507 + x = xScale(0)
  508 + } else if (i === 1) { // part2
  509 + x = xScale(0) + partWidth + partBetweenPadding
  510 + } else if (i === 2) { // part3
  511 + x = xScale(0) + partWidth * 2 + partBetweenPadding * 2
  512 + }
  513 + y = yScale(0)
  514 + return `translate(${x}, ${y})`
  515 + })
  516 +
  517 + // ------------ 2、添加part的上半部分 ----------------//
  518 + itemsEnter.append('rect')
  519 + .classed('main', true)
  520 + .attr('stroke-dasharray', function (d, i) {
  521 + if (i === 0) {
  522 + return null
  523 + } else {
  524 + return "4,2"
  525 + }
  526 + })
  527 + .attr('width', function (d, i) {
  528 + if (i === 1 ) { // part2
  529 + if (showType === 0 || showType === 1) {
  530 + return partWidth
  531 + } else if (showType === 2 || showType === 3) {
  532 + return partWidth * 2 + partBetweenPadding
  533 + } else {
  534 + return partWidth
  535 + }
  536 + } else {
  537 + return partWidth
  538 + }
  539 + })
  540 + .attr('height', partHeight + 'px')
  541 + itemsUpdate.select('rect.main')
  542 + .attr('stroke-dasharray', function (d, i) {
  543 + if (i === 0) {
  544 + return null
  545 + } else {
  546 + return "4,2"
  547 + }
  548 + })
  549 + .attr('width', function (d, i) {
  550 + if (i === 1 ) { // part2
  551 + if (showType === 0 || showType === 1) {
  552 + return partWidth
  553 + } else if (showType === 2 || showType === 3) {
  554 + return partWidth * 2 + partBetweenPadding
  555 + } else {
  556 + return partWidth
  557 + }
  558 + } else {
  559 + return partWidth
  560 + }
  561 + })
  562 + .attr('height', partHeight + 'px')
  563 +
  564 + itemsEnter.append('rect')
  565 + .classed('titleBackground', true)
  566 + .attr('width', function (d, i) {
  567 + if (i === 1) {
  568 + if (showType === 0 || showType === 1) {
  569 + return partWidth - 2
  570 + } else if (showType === 2 || showType === 3) {
  571 + return partWidth * 2 + partBetweenPadding - 2
  572 + } else {
  573 + return partWidth - 2
  574 + }
  575 + } else {
  576 + return partWidth - 2
  577 + }
  578 + })
  579 + .attr('height', function (d, i) {
  580 + if (i === 0) {
  581 + return 0
  582 + } else {
  583 + return 48
  584 + }
  585 + })
  586 + .style('fill', function (d, i) {
  587 + if (i === 0) {
  588 + return self.part1_background_color
  589 + } else if (i === 1) {
  590 + return self.part2_title1_background_color
  591 + } else if (i === 2) {
  592 + return self.part3_title1_background_color
  593 + }
  594 + })
  595 + .attr('x', 1)
  596 + .attr('y', 1)
  597 + itemsUpdate.select('rect.titleBackground')
  598 + .attr('width', function (d, i) {
  599 + if (i === 1) {
  600 + if (showType === 0 || showType === 1) {
  601 + return partWidth - 2
  602 + } else if (showType === 2 || showType === 3) {
  603 + return partWidth * 2 + partBetweenPadding - 2
  604 + } else {
  605 + return partWidth - 2
  606 + }
  607 + } else {
  608 + return partWidth - 2
  609 + }
  610 + })
  611 +
  612 + itemsEnter.append('g')
  613 + .classed('titleBound', true)
  614 + .attr('transform', 'translate(10, 10)')
  615 + itemsUpdate.select('g.titleBound')
  616 + .attr('transform', function (d, i) {
  617 +
  618 + })
  619 + itemsEnter.select('g.titleBound')
  620 + .select(function (d, i) {return i === 0 ? this : null})
  621 + .append('image')
  622 + .classed('carIcon', true)
  623 + .attr('x', 0) // 指定x位置,TODO:之后这个属性可能需要可编辑
  624 + .attr('y', 15) // 指定y位置,TODO:之后这个属性可能需要可编辑
  625 + .attr('href', CarIcon)
  626 + .attr('width', 50) // 指定宽度,TODO:之后这个属性可能需要可编辑
  627 + .attr('height', 50) // 指定高度,TODO:之后这个属性可能需要可编辑
  628 + itemsEnter.select('g.titleBound')
  629 + .append('text')
  630 + .classed('title', true)
  631 + .text(function (d, i) {
  632 + if (i === 0) {
  633 + return d.lineName
  634 + } else if (i === 1) {
  635 + return d.text1
  636 + } else if (i === 2) {
  637 + return d.text1
  638 + } else {
  639 + return '-'
  640 + }
  641 + })
  642 + .style('font-size', function (d, i) {
  643 + if (i === 0) {
  644 + return self.part1_line_name_font_size
  645 + } else if (i === 1) {
  646 + return self.part2_title1_font_size
  647 + } else if (i === 2) {
  648 + return self.part3_title1_font_size
  649 + }
  650 + })
  651 + .style('fill', function (d, i) {
  652 + if (i === 0) {
  653 + return self.part1_line_name_font_color
  654 + } else if (i === 1) {
  655 + return self.part2_title1_font_color
  656 + } else if (i === 2) {
  657 + return self.part3_title1_font_color
  658 + }
  659 + })
  660 + .attr('x', function (d, i) {
  661 + if (i === 0) {
  662 + return 60
  663 + } else {
  664 + return 0
  665 + }
  666 + })
  667 + .attr('y', function (d, i) {
  668 + return this.getBBox().height - 10
  669 + })
  670 + itemsUpdate.select('g.titleBound')
  671 + .attr('transform', function (d, i) {
  672 + let g_part_bounds = svg.select('g.part:nth-child(' + (i + 1) +')').node().getBBox()
  673 + let title_bounds = this.getBBox()
  674 + let dx = 1
  675 + let dy = 1
  676 +
  677 + if (i === 0) {
  678 + dx = (g_part_bounds.width - title_bounds.width) / 2 - title_bounds.x
  679 + dy = (g_part_bounds.height / 2 - title_bounds.height) / 2 - title_bounds.y
  680 + } else {
  681 + dx = (g_part_bounds.width - title_bounds.width) / 2 - title_bounds.x
  682 + dy = (48 - title_bounds.height) / 2 - title_bounds.y
  683 + }
  684 + if (dx < 0) {
  685 + dx = 1
  686 + }
  687 + if (dy < 0) {
  688 + dy = 1
  689 + }
  690 + return `translate(${dx}, ${dy})`
  691 + })
  692 +
  693 + // ------------ 3、添加part的下半部分 ----------------//
  694 + // ------------ 3-1、part1部分 -------------//
  695 + itemsEnter.select(function (d, i) {
  696 + return i === 0 ? this : null
  697 + }).append('g')
  698 + .classed('content1Bound', true)
  699 + .attr('transform', 'translate(10, 10)')
  700 + itemsEnter.select('g.content1Bound')
  701 + .append('text')
  702 + .classed('content1', true)
  703 + .text(function (d) {
  704 + return d.text1
  705 + })
  706 + .attr('title', function (d) {
  707 + return d.text1
  708 + })
  709 + .attr('y', 0)
  710 + .style('font-size', self.part1_terminal_stop_font_size)
  711 + .style('fill', self.part1_terminal_stop_font_color)
  712 + itemsUpdate.select('g.content1Bound')
  713 + .attr('transform', function (d, i) {
  714 + if (i === 0) {
  715 + let rect_part1_bounds = svg.select('rect.main:nth-child(1)').node().getBBox()
  716 + let g_content1_bounds = this.getBBox()
  717 + let dx = (rect_part1_bounds.width - g_content1_bounds.width) / 2 - g_content1_bounds.x
  718 + let dy = (rect_part1_bounds.height / 4 - g_content1_bounds.height) - g_content1_bounds.y
  719 + + rect_part1_bounds.height / 2
  720 + if (dx < 0) {
  721 + dx = 1
  722 + }
  723 + if (dy < 0) {
  724 + dy = 1
  725 + }
  726 + return `translate(${dx}, ${dy})`
  727 + }
  728 + })
  729 +
  730 + itemsEnter.select(function (d, i) {
  731 + return i === 0 ? this : null
  732 + }).append('g')
  733 + .classed('content2Bound', true)
  734 + .attr('transform', 'translate(10, 10)')
  735 + itemsEnter.select('g.content2Bound')
  736 + .append('text')
  737 + .classed('content2', true)
  738 + .text(function (d) {
  739 + return d.text2
  740 + })
  741 + .attr('title', function (d) {
  742 + return d.text2
  743 + })
  744 + .attr('y', 0)
  745 + .style('font-size', self.part1_terminal_stop_font_size)
  746 + .style('fill', self.part1_terminal_stop_font_color)
  747 + itemsUpdate.select('g.content2Bound')
  748 + .attr('transform', function (d, i) {
  749 + if (i === 0) {
  750 + let rect_part1_bounds = svg.select('rect.main:nth-child(1)').node().getBBox()
  751 + let g_content1_bounds = this.getBBox()
  752 + let dx = (rect_part1_bounds.width - g_content1_bounds.width) / 2 - g_content1_bounds.x
  753 + let dy = - g_content1_bounds.y
  754 + + rect_part1_bounds.height * 0.75
  755 + if (dx < 0) {
  756 + dx = 1
  757 + }
  758 + if (dy < 0) {
  759 + dy = 1
  760 + }
  761 + return `translate(${dx}, ${dy})`
  762 + }
  763 + })
  764 +
  765 +
  766 + // ------------ 3-2、part2部分 -------------//
  767 + let boundLineFun = d3.line()
  768 + itemsEnter.select(function (d, i) {
  769 + return i === 1 ? this : null
  770 + }).append('path')
  771 + .classed('bound', true)
  772 + .attr('d', function (d) {
  773 + return boundLineFun([
  774 + [partWidth / 2, 48],
  775 + [partWidth / 2, partHeight]
  776 + ])
  777 + })
  778 + itemsUpdate.select('path.bound')
  779 + .attr('d', function (d) {
  780 + return boundLineFun([
  781 + [partWidth / 2, 48],
  782 + [partWidth / 2, partHeight]
  783 + ])
  784 + })
  785 +
  786 + itemsEnter.select(function (d, i) {
  787 + return i === 1 ? this : null
  788 + }).append('g')
  789 + .classed('content3Bound', true)
  790 + .attr('transform', 'translate(10, 10)')
  791 + itemsEnter.select('g.content3Bound')
  792 + .append('text')
  793 + .classed('content3', true)
  794 + .text(function (d) {
  795 + return d.text2
  796 + })
  797 + .attr('title', function (d) {
  798 + return d.text2
  799 + })
  800 + .style('font-size', self.part2_title2_font_size)
  801 + .style('fill', self.part2_title2_font_color)
  802 + itemsUpdate.select('g.content3Bound')
  803 + .attr('transform', function (d, i) {
  804 + if (i === 1) {
  805 + let rect_part2_bounds = d3.select(this.parentNode).select('rect.main').node().getBBox()
  806 + let g_bounds = this.getBBox()
  807 + let dx = (rect_part2_bounds.width / 2 - g_bounds.width) / 2 - g_bounds.x
  808 + let dy = 48 - g_bounds.y
  809 + if (dx < 0) {
  810 + dx = 1
  811 + }
  812 + if (dy < 0) {
  813 + dy = 1
  814 + }
  815 + return `translate(${dx}, ${dy})`
  816 + }
  817 + })
  818 +
  819 + itemsEnter.select(function (d, i) {
  820 + return i === 1 ? this : null
  821 + }).append('g')
  822 + .classed('content4Bound', true)
  823 + .attr('transform', 'translate(10, 10)')
  824 + itemsEnter.select('g.content4Bound')
  825 + .append('text')
  826 + .classed('content4', true)
  827 + .text(function (d) {
  828 + return d.text3
  829 + })
  830 + .attr('title', function (d) {
  831 + return d.text3
  832 + })
  833 + .style('font-size', self.part2_title2_font_size)
  834 + .style('fill', self.part2_title2_font_color)
  835 + itemsUpdate.select('g.content4Bound')
  836 + .attr('transform', function (d, i) {
  837 + if (i === 1) {
  838 + let rect_part2_bounds = d3.select(this.parentNode).select('rect.main').node().getBBox()
  839 + let g_bounds = this.getBBox()
  840 + let dx = (rect_part2_bounds.width / 2 - g_bounds.width) / 2 - g_bounds.x
  841 + + rect_part2_bounds.width / 2
  842 + let dy = 48 - g_bounds.y
  843 + if (dx < 0) {
  844 + dx = 1
  845 + }
  846 + if (dy < 0) {
  847 + dy = 1
  848 + }
  849 + return `translate(${dx},${dy})`
  850 + }
  851 + })
  852 +
  853 + itemsEnter.select(function (d, i) {
  854 + return i === 1 ? this : null
  855 + }).append('g')
  856 + .classed('content5Bound', true)
  857 + .attr('transform', 'translate(10, 10)')
  858 + itemsEnter.select('g.content5Bound')
  859 + .append('text')
  860 + .classed('content5_left', true)
  861 + .text(function (d) {
  862 + return d.currentArrivalMinutes_left
  863 + })
  864 + .attr('title', function (d) {
  865 + return d.currentArrivalMinutes_left
  866 + })
  867 + .style('font-size', self.part2_arrival_time_minutes_left_font_size)
  868 + .style('fill', self.part2_arrival_time_minutes_left_font_color)
  869 + itemsEnter.select('g.content5Bound')
  870 + .append('text')
  871 + .classed('content5_right', true)
  872 + .text(function (d) {
  873 + return d.currentArrivalMinutes_right
  874 + })
  875 + .attr('title', function (d) {
  876 + return d.currentArrivalMinutes_right
  877 + })
  878 + .style('font-size', self.part2_arrival_time_minutes_right_font_size)
  879 + .style('fill', self.part2_arrival_time_minutes_right_font_color)
  880 + .attr('x', function () {
  881 + let left_bound = svg.select('text.content5_left').node().getBBox()
  882 + return left_bound.width + 2
  883 + })
  884 + itemsUpdate.select('g.content5Bound')
  885 + .attr('transform', function (d, i) {
  886 + if (i === 1) {
  887 + let rect_part2_bounds = d3.select(this.parentNode).select('rect.main').node().getBBox()
  888 + let g_bounds = this.getBBox()
  889 + let dx = (rect_part2_bounds.width / 2 - g_bounds.width) / 2 - g_bounds.x
  890 + let dy = (rect_part2_bounds.height / 2 - g_bounds.height) / 2 - g_bounds.y
  891 + + rect_part2_bounds.height / 2
  892 + if (dx < 0) {
  893 + dx = 1
  894 + }
  895 + if (dy < 0) {
  896 + dy = 1
  897 + }
  898 + return `translate(${dx}, ${dy})`
  899 + }
  900 + })
  901 +
  902 + itemsEnter.select(function (d, i) {
  903 + return i === 1 ? this : null
  904 + }).append('g')
  905 + .classed('content6Bound', true)
  906 + .attr('transform', 'translate(10, 10)')
  907 + itemsEnter.select('g.content6Bound')
  908 + .append('text')
  909 + .classed('content6_left', true)
  910 + .text(function (d) {
  911 + return d.currentFromStations_left
  912 + })
  913 + .attr('title', function (d) {
  914 + return d.currentFromStations_left
  915 + })
  916 + .style('font-size', self.part2_from_stops_left_font_size)
  917 + .style('fill', self.part2_from_stops_left_font_color)
  918 + itemsEnter.select('g.content6Bound')
  919 + .append('text')
  920 + .classed('content6_right', true)
  921 + .text(function (d) {
  922 + return d.currentFromStations_right
  923 + })
  924 + .attr('title', function (d) {
  925 + return d.currentFromStations_right
  926 + })
  927 + .style('font-size', self.part2_from_stops_right_font_size)
  928 + .style('fill', self.part2_from_stops_right_font_color)
  929 + .attr('x', function () {
  930 + let left_bound = svg.select('text.content6_left').node().getBBox()
  931 + return left_bound.width + 2
  932 + })
  933 + itemsUpdate.select('g.content6Bound')
  934 + .attr('transform', function (d, i) {
  935 + if (i === 1) {
  936 + let rect_part2_bounds = d3.select(this.parentNode).select('rect.main').node().getBBox()
  937 + let g_bounds = this.getBBox()
  938 + let dx = (rect_part2_bounds.width / 2 - g_bounds.width) / 2 - g_bounds.x
  939 + + rect_part2_bounds.width / 2
  940 + let dy = (rect_part2_bounds.height / 2 - g_bounds.height) / 2 - g_bounds.y
  941 + + rect_part2_bounds.height / 2
  942 + if (dx < 0) {
  943 + dx = 1
  944 + }
  945 + if (dy < 0) {
  946 + dy = 1
  947 + }
  948 + return `translate(${dx}, ${dy})`
  949 + }
  950 + })
  951 +
  952 + // ------------ 3-3、part3部分 -------------//
  953 + itemsEnter.select(function (d, i) {
  954 + return i === 2 ? this : null
  955 + }).append('g')
  956 + .classed('contentAllBound', true)
  957 + .attr('transform', 'translate(10, 10)')
  958 + itemsEnter.select('g.contentAllBound')
  959 + .append('text')
  960 + .classed('content', true)
  961 + .text(function (d) {
  962 + return d.text2
  963 + })
  964 + .attr('title', function (d) {
  965 + return d.text2
  966 + })
  967 + .style('font-size', self.part3_title2_font_size)
  968 + .style('fill', self.part3_title2_font_color)
  969 + itemsEnter.select('g.contentAllBound')
  970 + .append('text')
  971 + .classed('arrivalTime', true)
  972 + .text(function (d) {
  973 + return d.nextArrivalTime
  974 + })
  975 + .style('font-size', self.part3_arrival_time_font_size)
  976 + .style('fill', self.part3_arrival_time_font_color)
  977 + .attr('x', 100)
  978 + itemsUpdate.select('g.contentAllBound')
  979 + .attr('transform', function (d, i) {
  980 + if (i === 2) {
  981 + let rect_part3_bounds = d3.select(this.parentNode).select('rect.main').node().getBBox()
  982 + let g_content_bounds = this.getBBox()
  983 + let dx = (rect_part3_bounds.width - g_content_bounds.width) / 2 - g_content_bounds.x
  984 + let dy = (rect_part3_bounds.height - 48 - g_content_bounds.height) / 2 - g_content_bounds.y + 48
  985 + if (dx < 0) {
  986 + dx = 1
  987 + }
  988 + if (dy < 0) {
  989 + dy = 1
  990 + }
  991 + return `translate(${dx}, ${dy})`
  992 + }
  993 + })
  994 +
  995 +
  996 + }
  997 +
  998 + }
  999 +
  1000 +}
... ...
front-end/h5/src/components/core/plugins/bsth/mhgj/chart/models/MhgjEBusStopLineChartData.js 0 → 100644
  1 +// 电子站牌数据信息
  2 +class MhgjEBusStopLineChartData {
  3 + /**
  4 + * 构造函数。
  5 + */
  6 + constructor () {
  7 + /** 线路名称(如:548路) */
  8 + this._lineName = null
  9 + /** 当前线路方向终点站名称(如:延安西路华山路) */
  10 + this._terminalStationName = null
  11 + /** 本班车到达时间(如:10:52) */
  12 + this._currentArrivalTime = null
  13 + /** 本班车到达分钟(如:15分钟) */
  14 + this._currentArrivalMinutes = null;
  15 + /** 本班车距离当前站几站(如:8站) */
  16 + this._currentFromStations = null
  17 + /** 本班车距离当前站分钟(如:27分钟) */
  18 + this._currentFromMinutes = null;
  19 + /** 下一班车预计到站时间(如:10:49) */
  20 + this._nextArrivalTime = null;
  21 +
  22 + /**
  23 + * 根据外部获取的数据多少,确定显示的类型(与前端对应)
  24 + * 0:包含三个完整部分的显示,part1,part2,part3(距离本站一站时,part2显示到站时间)
  25 + * 1:包含三个完整部分的显示,part1,part2,part3
  26 + * 2:包含两个完整部分的显示,part1,part2(part2部分显示更多的数据)
  27 + * 3:包含三个完整部分的显示,part1,part2(part2显示数据为-)
  28 + */
  29 + this._showType = null;
  30 + }
  31 +
  32 + setLineName (lineName) {
  33 + this._lineName = lineName
  34 + return this
  35 + }
  36 + setTerminalStationName (stationName) {
  37 + this._terminalStationName = stationName
  38 + return this
  39 + }
  40 + setCurrentArrivalTime (arrivalTime) {
  41 + this._currentArrivalTime = arrivalTime
  42 + return this
  43 + }
  44 + setCurrentArrivalMinutes (arrivalMinutes) {
  45 + this._currentArrivalMinutes = arrivalMinutes
  46 + return this
  47 + }
  48 + setCurrentFromStations (stations) {
  49 + this._currentFromStations = stations
  50 + return this
  51 + }
  52 + setCurrentFromMinutes (time) {
  53 + this._currentFromMinutes = time
  54 + return this
  55 + }
  56 + setNextArrivalTime (time) {
  57 + this._nextArrivalTime = time
  58 + return this
  59 + }
  60 + setShowType (type) {
  61 + this._showType = type
  62 + return this
  63 + }
  64 +
  65 + get lineName () {
  66 + return this._lineName
  67 + }
  68 + get terminalStationName () {
  69 + return this._terminalStationName
  70 + }
  71 + get currentArrivalTime () {
  72 + return this._currentArrivalTime
  73 + }
  74 + get currentArrivalMinutes () {
  75 + return this._currentArrivalMinutes
  76 + }
  77 + get currentFromStations () {
  78 + return this._currentFromStations
  79 + }
  80 + get currentFromMinutes () {
  81 + return this._currentFromMinutes
  82 + }
  83 + get nextArrivalTime () {
  84 + return this._nextArrivalTime
  85 + }
  86 + get showType () {
  87 + return this._showType
  88 + }
  89 +
  90 + generateSvgData () {
  91 + // 根据内部数据产生svg用数据
  92 + let showData = [];
  93 + if (this._showType === 0) {
  94 + showData.push({
  95 + lineName: this._lineName,
  96 + text1: '开往',
  97 + text2: this._terminalStationName
  98 + });
  99 + showData.push({
  100 + text1: "本班车",
  101 + text2: "到达时间",
  102 + text3: "距本站",
  103 + currentArrivalTime: this._currentArrivalTime,
  104 + currentFromStations_left: this._currentFromStations,
  105 + currentFromStations_right: "站"
  106 + })
  107 + showData.push({
  108 + text1: "下一班车",
  109 + text2: "预计到站",
  110 + nextArrivalTime: this._nextArrivalTime
  111 + })
  112 +
  113 + } else if (this._showType === 1) {
  114 + showData.push({
  115 + lineName: this._lineName,
  116 + text1: '开往',
  117 + text2: this._terminalStationName
  118 + });
  119 + showData.push({
  120 + text1: "本班车",
  121 + text2: "到达时间",
  122 + text3: "距本站",
  123 + currentArrivalMinutes_left: this._currentArrivalMinutes,
  124 + currentArrivalMinutes_right: "分钟",
  125 + currentFromStations_left: this._currentFromStations,
  126 + currentFromStations_right: "站"
  127 + })
  128 + showData.push({
  129 + text1: "下一班车",
  130 + text2: "预计到站",
  131 + nextArrivalTime: this._nextArrivalTime
  132 + })
  133 + } else if (this._showType === 2) {
  134 + showData.push({
  135 + lineName: this._lineName,
  136 + text1: '开往',
  137 + text2: this._terminalStationName
  138 + });
  139 + showData.push({
  140 + text1: "本班车",
  141 + text2: "到达时间",
  142 + text3: "距本站",
  143 + currentArrivalTime: this._currentArrivalTime,
  144 + currentFromStations_left: this._currentFromStations,
  145 + currentFromStations_right: "站",
  146 + currentFromMinutes_left: this._currentFromMinutes,
  147 + currentFromMinutes_right: "分钟"
  148 + })
  149 +
  150 + } else if (this._showType === 3) {
  151 + showData.push({
  152 + lineName: this._lineName,
  153 + text1: '开往',
  154 + text2: this._terminalStationName
  155 + });
  156 + showData.push({
  157 + text1: "本班车",
  158 + text2: "到达时间",
  159 + text3: "距本站",
  160 + currentFromMinutes_left: "-",
  161 + currentFromMinutes_right: "分钟",
  162 + currentFromStations: "-"
  163 + })
  164 + }
  165 +
  166 + return showData
  167 + }
  168 +
  169 +
  170 + /**
  171 + * 产生数据。
  172 + * @param json 外部json对象
  173 + */
  174 + static generateData (json) {
  175 + // TODO;根据外部json,决定构造哪种showType的数据
  176 + }
  177 +
  178 + /**
  179 + * 产生测试数据1,包含三个完整部分的显示,part1,part2,part3
  180 + */
  181 + static generateTestData_type1 () {
  182 + let testData = new MhgjEBusStopLineChartData()
  183 + return testData
  184 + .setShowType(1)
  185 + .setLineName("浦江12路")
  186 + .setTerminalStationName("漕河泾综合保税区")
  187 + .setCurrentArrivalMinutes("21")
  188 + .setCurrentFromStations("1")
  189 + .setNextArrivalTime("11:47")
  190 + }
  191 +
  192 + /**
  193 + * 产生测试数据2,包含两个完整部分的显示,part1,part2(part2部分显示更多的数据)
  194 + */
  195 + static generateTestData_type2 () {
  196 + let testData = new MhgjEBusStopLineChartData()
  197 + return testData
  198 + .setShowType(2)
  199 + .setLineName("700路")
  200 + .setTerminalStationName("芙蓉江路仙霞路")
  201 + .setCurrentArrivalTime("16:00")
  202 + .setCurrentFromStations("2")
  203 + .setCurrentFromMinutes("3")
  204 +
  205 + }
  206 +
  207 + /**
  208 + * 产生测试数据3,包含三个完整部分的显示,part1,part2(part2显示数据为-)
  209 + */
  210 + static generateTestData_type3 () {
  211 + let testData = new MhgjEBusStopLineChartData()
  212 + return testData
  213 + .setShowType(3)
  214 + .setLineName("700路")
  215 + .setTerminalStationName("芙蓉江路仙霞路")
  216 + .setCurrentArrivalTime("-")
  217 + .setCurrentFromStations("-")
  218 + }
  219 +
  220 +}
  221 +
  222 +export {
  223 + MhgjEBusStopLineChartData
  224 +}
  225 +
  226 +
... ...
front-end/h5/src/components/core/plugins/bsth/mhgj/chart/svgicon/car.svg 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
  3 +<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="50px" height="50px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
  4 +<g><path style="opacity:1" fill="#1f78bd" d="M 19.5,-0.5 C 22.8333,-0.5 26.1667,-0.5 29.5,-0.5C 39.8333,2.5 46.5,9.16667 49.5,19.5C 49.5,22.8333 49.5,26.1667 49.5,29.5C 46.5,39.8333 39.8333,46.5 29.5,49.5C 26.1667,49.5 22.8333,49.5 19.5,49.5C 9.16667,46.5 2.5,39.8333 -0.5,29.5C -0.5,26.1667 -0.5,22.8333 -0.5,19.5C 2.5,9.16667 9.16667,2.5 19.5,-0.5 Z"/></g>
  5 +<g><path style="opacity:1" fill="#377fbf" d="M 13.5,14.5 C 13.5,13.8333 13.5,13.1667 13.5,12.5C 20.9818,11.508 28.6484,11.1746 36.5,11.5C 36.5,12.8333 36.5,14.1667 36.5,15.5C 28.6484,15.8254 20.9818,15.492 13.5,14.5 Z"/></g>
  6 +<g><path style="opacity:1" fill="#1d74ba" d="M 13.5,16.5 C 17.1667,16.5 20.8333,16.5 24.5,16.5C 24.5,19.5 24.5,22.5 24.5,25.5C 20.8333,25.5 17.1667,25.5 13.5,25.5C 13.5,22.5 13.5,19.5 13.5,16.5 Z"/></g>
  7 +<g><path style="opacity:1" fill="#bdd6ea" d="M 12.5,11.5 C 12.5,12.1667 12.8333,12.5 13.5,12.5C 13.5,13.1667 13.5,13.8333 13.5,14.5C 12.1667,15.1667 12.1667,15.8333 13.5,16.5C 13.5,19.5 13.5,22.5 13.5,25.5C 17.1667,25.5 20.8333,25.5 24.5,25.5C 24.8333,26.8333 25.1667,26.8333 25.5,25.5C 29.1667,25.5 32.8333,25.5 36.5,25.5C 36.5,26.1667 36.5,26.8333 36.5,27.5C 28.8333,27.5 21.1667,27.5 13.5,27.5C 13.5,28.5 13.5,29.5 13.5,30.5C 12.8333,30.5 12.1667,30.5 11.5,30.5C 11.8285,26.646 11.1618,22.9793 9.5,19.5C 10.7322,16.7892 11.7322,14.1226 12.5,11.5 Z"/></g>
  8 +<g><path style="opacity:1" fill="#2276bb" d="M 36.5,27.5 C 29.8933,29.705 23.06,30.0383 16,28.5C 14.9701,28.8361 14.4701,29.5028 14.5,30.5C 14.1667,30.5 13.8333,30.5 13.5,30.5C 13.5,29.5 13.5,28.5 13.5,27.5C 21.1667,27.5 28.8333,27.5 36.5,27.5 Z"/></g>
  9 +<g><path style="opacity:1" fill="#5090c8" d="M 36.5,27.5 C 37.404,28.209 37.7373,29.209 37.5,30.5C 29.8333,30.5 22.1667,30.5 14.5,30.5C 14.4701,29.5028 14.9701,28.8361 16,28.5C 23.06,30.0383 29.8933,29.705 36.5,27.5 Z"/></g>
  10 +<g><path style="opacity:1" fill="#d9e7f3" d="M 31.5,39.5 C 27.8274,37.6823 23.8274,37.0157 19.5,37.5C 19.5,38.5 19.5,39.5 19.5,40.5C 17.8333,40.5 16.1667,40.5 14.5,40.5C 13.8611,38.2396 12.6945,36.2396 11,34.5C 10.235,32.9343 10.4017,31.6009 11.5,30.5C 12.1667,30.5 12.8333,30.5 13.5,30.5C 13.8333,30.5 14.1667,30.5 14.5,30.5C 22.1667,30.5 29.8333,30.5 37.5,30.5C 37.7373,29.209 37.404,28.209 36.5,27.5C 36.5,26.8333 36.5,26.1667 36.5,25.5C 36.5,22.5 36.5,19.5 36.5,16.5C 32.8333,16.5 29.1667,16.5 25.5,16.5C 25.5,19.5 25.5,22.5 25.5,25.5C 25.1667,26.8333 24.8333,26.8333 24.5,25.5C 24.5,22.5 24.5,19.5 24.5,16.5C 20.8333,16.5 17.1667,16.5 13.5,16.5C 12.1667,15.8333 12.1667,15.1667 13.5,14.5C 20.9818,15.492 28.6484,15.8254 36.5,15.5C 36.5,14.1667 36.5,12.8333 36.5,11.5C 28.6484,11.1746 20.9818,11.508 13.5,12.5C 12.8333,12.5 12.5,12.1667 12.5,11.5C 12.6107,10.8826 12.944,10.3826 13.5,10C 21.1667,9.33333 28.8333,9.33333 36.5,10C 37,10.5 37.5,11 38,11.5C 38.3302,14.324 39.1635,16.9906 40.5,19.5C 40.3333,20.1667 40.1667,20.8333 40,21.5C 39.6667,20.5 39.3333,19.5 39,18.5C 38.2807,23.2007 38.4474,27.8673 39.5,32.5C 38.8094,35.3535 37.4761,37.8535 35.5,40C 33.9343,40.765 32.6009,40.5983 31.5,39.5 Z"/></g>
  11 +<g><path style="opacity:1" fill="#327ebf" d="M 12.5,31.5 C 21.1922,31.1686 29.8589,31.502 38.5,32.5C 34.1667,32.8333 29.8333,33.1667 25.5,33.5C 20.7784,33.4921 16.4451,32.8255 12.5,31.5 Z"/></g>
  12 +<g><path style="opacity:1" fill="#2276bb" d="M 36.5,25.5 C 32.8333,25.5 29.1667,25.5 25.5,25.5C 25.5,22.5 25.5,19.5 25.5,16.5C 29.1667,16.5 32.8333,16.5 36.5,16.5C 36.5,19.5 36.5,22.5 36.5,25.5 Z"/></g>
  13 +<g><path style="opacity:1" fill="#78acd6" d="M 13.5,34.5 C 21.1955,34.1692 28.8622,34.5025 36.5,35.5C 32.6667,35.8333 28.8333,36.1667 25,36.5C 20.771,36.4898 16.9377,35.8232 13.5,34.5 Z"/></g>
  14 +<g><path style="opacity:1" fill="#5f98cc" d="M 15.5,37.5 C 16.675,37.281 17.675,37.6143 18.5,38.5C 16.9483,39.7979 15.9483,39.4646 15.5,37.5 Z"/></g>
  15 +<g><path style="opacity:1" fill="#649acd" d="M 31.5,39.5 C 31.9483,37.5354 32.9483,37.2021 34.5,38.5C 33.675,39.3857 32.675,39.719 31.5,39.5 Z"/></g>
  16 +</svg>
... ...
front-end/h5/src/components/core/plugins/bsth/mhgj/chart/svgicon/tools.svg 0 → 100644
  1 +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20.753 23c-.868 0-1.684-.338-2.297-.951l-10.602-11.174-.607.652-1.929 1.93-5.318-5.32 2.51-2.511.683.459c.026.015.171.086.304.086.054 0 .12-.008.215-.104.195-.195.312-.471.475-.854.323-.759.765-1.801 2.174-2.861 1.19-.897 2.66-1.352 4.367-1.352 2.713 0 5.107 1.163 5.208 1.212l-.341 1.891c-1.658.166-4.558.762-3.318 2.007l10.786 11.358c.6.602.937 1.417.937 2.284s-.337 1.683-.951 2.296c-.614.614-1.429.952-2.296.952zm-9.341-11.368l8.47 9.017c.444.443 1.28.458 1.753-.013.235-.236.366-.55.366-.883 0-.333-.13-.647-.367-.884l-8.457-9.002-1.765 1.765zm-8.585-3.495l2.492 2.493.021-.022c-.138-.558-.058-1.225.524-1.806.346-.346.777-.529 1.25-.529.651 0 1.307.34 2.004 1.039l.893.893 1.766-1.767-.915-.915c-1.171-1.172-1.027-2.24-.838-2.772.246-.689.807-1.258 1.661-1.695-.312-.036-.633-.057-.958-.057-1.264 0-2.329.319-3.165.949-.98.738-1.25 1.374-1.537 2.047-.212.5-.431 1.016-.901 1.485-.45.452-1.013.69-1.627.69-.227 0-.437-.032-.623-.08l-.047.047zm13.553-.619l3.336-3.296c.169-.17.443-.168.611 0 .169.17.169.442.001.611l-3.353 3.313.866.912 3.375-3.335c.168-.169.441-.168.611.001.168.168.169.441 0 .609l-3.392 3.352 1.011 1.064 3.679-3.637c.584-.582.875-1.346.875-2.11 0-.768-.293-1.537-.88-2.125-.585-.585-1.35-.877-2.114-.877-.766 0-1.53.293-2.114.877l-3.569 3.528 1.057 1.113zm-7.233 7.65l-4.127 3.993c-.229.229-.503.407-.79.558l-.58.302-1.025 2.146.833.833 2.101-1.07.301-.58c.151-.286.347-.545.574-.774l4.091-3.958-1.378-1.45z"/></svg>
0 2 \ No newline at end of file
... ...
front-end/h5/src/components/core/plugins/index.js
... ... @@ -30,6 +30,8 @@ import BsthDatetime from &#39;core/plugins/bsth/bsth-datetime&#39;
30 30 import EBusStopLineChart from 'core/plugins/bsth/lggj/chart/eBusStop-line-chart'
31 31 import EBusStopLineChartList from 'core/plugins/bsth/lggj/list/eBusStop-line-chart-list'
32 32  
  33 +import MhgjEBusStopLineChart from 'core/plugins/bsth/mhgj/chart/mhgj-eBusStop-line-chart'
  34 +
33 35 export const pluginsList = [
34 36 // {
35 37 // i18nTitle: {
... ... @@ -340,6 +342,18 @@ export const pluginsList = [
340 342 name: EBusStopLineChartList.name
341 343 },
342 344  
  345 + {
  346 + i18nTitle: {
  347 + 'en-US': 'MhgjEBusStopLineChart',
  348 + 'zh-CN': '电子站牌单线路模拟图2'
  349 + },
  350 + title: '电子站牌单线路模拟图2',
  351 + icon: 'list',
  352 + component: MhgjEBusStopLineChart,
  353 + visible: true,
  354 + name: MhgjEBusStopLineChart.name
  355 + },
  356 +
343 357 // {
344 358 // i18nTitle: {
345 359 // 'en-US': 'LineChart',
... ...