Commit 1e8c4d434ddee11b67ed31ca1f74978f51da7588

Authored by 徐烜
1 parent 09b8a3f5

其他公交公司用的公交电子站牌页面组件

1、新建othergj/linechart/chart目录,添加othergj-eBusStop-line-chart-list相关组件
front-end/h5/src/components/core/plugins/bsth/othergj/linechart/chart/bak.js 0 → 100644
  1 +/**
  2 + * 自定义线路模拟图组件
  3 + */
  4 +import PropTypes from '@luban-h5/plugin-common-props'
  5 +
  6 +import Utils from 'core/plugins/bsth/bsth-utils'
  7 +import { OgEBusStopData } from 'core/plugins/bsth/othergj/linechart/chart/models/OgEBusStopData'
  8 +
  9 +import './css/othergj-eBusStop-line-chart.css'
  10 +
  11 +import moment from 'moment'
  12 +
  13 +export default {
  14 + extra: {
  15 + defaultStyle: { // 默认属性
  16 + top: 0,
  17 + left: 0,
  18 + width: 700,
  19 + height: 230
  20 + }
  21 + },
  22 + name: 'othergj-eBusStop-line-chart',
  23 + data () {
  24 + this.private_svgns = 'http://www.w3.org/2000/svg' // svg元素名字空间
  25 + this.private_svg = null // 创建的根svg元素,由mounted钩子函数创建
  26 + // eslint-disable-next-line
  27 + this.private_jQuery = jQuery.noConflict() // jquery引用
  28 + // eslint-disable-next-line
  29 + this.private_d3 = d3 // d3引用
  30 +
  31 + return {
  32 + /**
  33 + * 监控外层元素的宽度高度变化
  34 + * 1、由于编辑器缩放,自定义组件无法监控,所以需要定义一个定时器监控最外层元素的大小变化
  35 + * 2、建议所有自定义组件,最外层都定义一个div包在自定义组件最外层,不要关联任何自定义的属性,样式对应编辑器的通用样式
  36 + */
  37 + watchWidthHeightTimer: {
  38 + timer: null,
  39 + count: 0,
  40 + millisecond: 1000
  41 + },
  42 +
  43 + // TODO:其他timer
  44 +
  45 + // 注意:css里设定了box-sizing: border-box;,所以组件本身的宽高包括了margin,padding,border
  46 + // 所以计算内部其他组件宽高需要减去margin,padding,border
  47 + component_width: 350, // 组件宽度
  48 + component_height: 400, // 组件高度
  49 + svg_width: 350, // svg图宽度
  50 + svg_height: 300, // svg图高度
  51 +
  52 + // TODO:其他属性
  53 +
  54 + // svg内部下部分线的属性(mounted初始计算一次)
  55 + down_line_x1: 0,
  56 + down_line_y1: 0,
  57 + down_line_x2: 0,
  58 + down_line_y2: 0,
  59 + down_line_x3: 0,
  60 + down_line_y3: 0,
  61 + down_line_x4: 0,
  62 + down_line_y4: 0,
  63 + down_line_x5: 0,
  64 + down_line_y5: 0,
  65 +
  66 + eBusStopData: null // 电子站牌数据(EBusStopData类型)
  67 + }
  68 +
  69 + },
  70 + computed: {
  71 + // TODO:其他计算属性
  72 + },
  73 + prop: {
  74 + useMode: PropTypes.string({ // 自定义使用模式,alone:(单独使用),child:(子组件)
  75 + defaultValue: 'alone',
  76 + label: '使用模式',
  77 + visible: false
  78 + }),
  79 + editorMode: PropTypes.string({ // 编辑模式会由编辑器自动注入(值:edit, preview)
  80 + defaultValue: 'edit',
  81 + label: '模式',
  82 + visible: false
  83 + }),
  84 + line_chart_outer_div_width: PropTypes.number({
  85 + defaultValue: 350,
  86 + label: 'line-chart-outer-div样式的div宽度',
  87 + visible: false
  88 + }),
  89 + line_chart_outer_div_height: PropTypes.number({
  90 + defaultValue: 300,
  91 + label: 'line-chart-outer-div样式的div高度',
  92 + visible: false
  93 + }),
  94 + eBusStopData_child: { // 作为子组件,父对象传值
  95 + type: OgEBusStopData,
  96 + default: function () {
  97 + return null
  98 + }
  99 + },
  100 +
  101 + // 数据属性
  102 + _flag_1_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="数据属性" class="bsth-line-item-divider"></hr>) } }),
  103 + // 图外层css
  104 + _flag_2_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图外层css属性" class="bsth-line-item-divider"></hr>) } }),
  105 + margin_left: PropTypes.number({ label: '图左边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  106 + margin_right: PropTypes.number({ label: '图右边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  107 + margin_top: PropTypes.number({ label: '图上边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  108 + margin_bottom: PropTypes.number({ label: '图底部margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  109 + border_size: PropTypes.number({ label: '图边框宽度', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  110 + background_color: PropTypes.color({ label: '背景颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  111 + // TODO:其他flag
  112 + _flag_5_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层线路图css属性" class="bsth-line-item-divider"></hr>) } }),
  113 + svg_background: PropTypes.color({ label: '线路图背景颜色', defaultValue: '#9EE0DF', layout: { prefixCls: 'bsth-line' } }),
  114 + chart_left_padding: PropTypes.number({ label: '内部线路图距离左边', defaultValue: 50, layout: { prefixCls: 'bsth-line' } }),
  115 + chart_right_padding: PropTypes.number({ label: '内部线路图距离右边', defaultValue: 50, layout: { prefixCls: 'bsth-line' } }),
  116 + chart_top_padding: PropTypes.number({ label: '内部线路图距离上边', defaultValue: 13, layout: { prefixCls: 'bsth-line' } }),
  117 + chart_up_line_path_s_width: PropTypes.number({ label: '上部分线宽度', defaultValue: 5, layout: { prefixCls: 'bsth-line' } }),
  118 + chart_up_line_path_s_color: PropTypes.color({ label: '上部分线颜色', defaultValue: '#008000', layout: { prefixCls: 'bsth-line' } }),
  119 + chart_up_line_circle_f_color_current: PropTypes.color({ label: '线圆圈填充色-当前站点', defaultValue: '#CB0808', layout: { prefixCls: 'bsth-line' } }),
  120 + chart_up_line_circle_f_color_before: PropTypes.color({ label: '线圆圈填充色-前面站点', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  121 + chart_up_line_circle_f_color_after: PropTypes.color({ label: '线圆圈填充色-后面站点', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  122 + chart_up_line_circle_r: PropTypes.number({ label: '线圆圈大小', defaultValue: 8, layout: { prefixCls: 'bsth-line' } }),
  123 + chart_station_text_top_padding: PropTypes.number({ label: '站点文字距离上边', defaultValue: 30, layout: { prefixCls: 'bsth-line' } }),
  124 + chart_station_text_font_size_current: PropTypes.number({ label: '站名字体大小-当前站点', defaultValue: 25, layout: { prefixCls: 'bsth-line' } }),
  125 + chart_station_text_font_size_before: PropTypes.number({ label: '站名字体大小-前面站点', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  126 + chart_station_text_font_size_after: PropTypes.number({ label: '站名字体大小-后面站点', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  127 + chart_station_text_length: PropTypes.number({ label: '站名长度', defaultValue: 100, layout: { prefixCls: 'bsth-line' } }),
  128 + chart_up_station_text_font_f_color_current: PropTypes.color({ label: '站名颜色-当前站点', defaultValue: '#060D37', layout: { prefixCls: 'bsth-line' } }),
  129 + chart_up_station_text_font_f_color_before: PropTypes.color({ label: '站名颜色-前面站点', defaultValue: '#9398B4', layout: { prefixCls: 'bsth-line' } }),
  130 + chart_up_station_text_font_f_color_after: PropTypes.color({ label: '站名颜色-后面站点', defaultValue: '#4556b6', layout: { prefixCls: 'bsth-line' } }),
  131 + _flag_6_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层下部分线css属性" class="bsth-line-item-divider"></hr>) } }),
  132 + down_line_left_padding: PropTypes.number({ label: '线距离左边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  133 + down_line_right_padding: PropTypes.number({ label: '线距离右边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  134 + down_line_bottom_padding: PropTypes.number({ label: '线距离下边', defaultValue: 6, layout: { prefixCls: 'bsth-line' } }),
  135 + down_line_s_width: PropTypes.number({ label: '线宽度', defaultValue: 5, layout: { prefixCls: 'bsth-line' } }),
  136 + down_line_s_color: PropTypes.color({ label: '线颜色', defaultValue: '#277461', layout: { prefixCls: 'bsth-line' } }),
  137 + down_line_arrow_width: PropTypes.number({ label: '箭头宽度', defaultValue: 55, layout: { prefixCls: 'bsth-line' } }),
  138 + down_line_arrow_height: PropTypes.number({ label: '箭头高度', defaultValue: 15, layout: { prefixCls: 'bsth-line' } }),
  139 + _flag_7_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="无数据提示css属性" class="bsth-line-item-divider"></hr>) } }),
  140 + empty_info_font_size: PropTypes.number({ label: '无数据提示文字字体大小', defaultValue: 30, layout: { prefixCls: 'bsth-line' } }),
  141 + empty_info_font_color: PropTypes.color({ label: '无数据提示文字字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } }),
  142 + empty_info_top_padding: PropTypes.number({ label: '无数据提示文字距离上边', defaultValue: 25, layout: { prefixCls: 'bsth-line' } })
  143 + },
  144 +
  145 + render () {
  146 + const innerDivStyle = {
  147 + 'width': this.component_width + 'px',
  148 + 'height': this.component_height + 'px',
  149 + 'border': this.border_size + 'px solid black',
  150 + 'margin-left': this.margin_left + 'px',
  151 + 'margin-right': this.margin_right + 'px',
  152 + 'margin-top': this.margin_top + 'px',
  153 + 'margin-bottom': this.margin_bottom + 'px',
  154 + 'background': this.background_color,
  155 + 'position': 'relative'
  156 + }
  157 +
  158 + const downLinePathD =
  159 + 'M' + this.down_line_x1 + ' ' + this.down_line_y1 + ' ' +
  160 + 'L' + this.down_line_x2 + ' ' + this.down_line_y2 + ' ' +
  161 + 'L' + this.down_line_x3 + ' ' + this.down_line_y3 + ' ' +
  162 + 'L' + this.down_line_x4 + ' ' + this.down_line_y4 + ' ' +
  163 + 'L' + this.down_line_x5 + ' ' + this.down_line_y5 + ' ' +
  164 + 'Z'
  165 +
  166 + const svgStyle = {
  167 + // 'width': this.line_width + 'px',
  168 + 'height': this.svg_height + 'px',
  169 + 'background-color': this.svg_background
  170 + }
  171 +
  172 + const emptyInfoStyle = {
  173 + 'height': '44px',
  174 + 'position': 'absolute',
  175 + 'left': '50%',
  176 + 'transform': 'translate(-50%, 0)',
  177 + '-webkit-transform': 'translate(-50%, 0)',
  178 + 'color': this.empty_info_font_color,
  179 + 'font-size': this.empty_info_font_size + 'px',
  180 + 'padding-top': this.empty_info_top_padding + 'px',
  181 + // 'font-family': 'Open Sans, sans-serif',
  182 + 'font-weight': 'bold'
  183 + }
  184 +
  185 + /* 最外层div对应编辑器的通用样式 */
  186 + return (
  187 + <div class="othergj-eBusStop-line-chart-outer-div">
  188 + <div style={innerDivStyle}>
  189 + <svg class="othergj-eBusStop-line-chart"
  190 + data-code={this.eBusStopData.lineCode}
  191 + style={svgStyle}>
  192 + <g class="arrow-wrap">
  193 + <path d={downLinePathD} style={{ 'fill': this.down_line_s_color }}></path>
  194 + </g>
  195 + </svg>
  196 + {
  197 + this.eBusStopData.routeStationDataList.length === 0 ? (<div style={emptyInfoStyle}>线路未开通,系统调试中</div>) : ''
  198 + }
  199 + </div>
  200 + </div>
  201 + )
  202 +
  203 + },
  204 + beforeMount () {
  205 + // 设置数据
  206 + if (this.useMode === 'alone') { // 单独使用,使用测试数据
  207 + this.eBusStopData = OgEBusStopData.generateTestData()
  208 + } else { // 自组件使用,使用父组件传值
  209 + this.eBusStopData = this.eBusStopData_child
  210 + }
  211 + },
  212 + mounted () {
  213 + // svg元素
  214 + this.private_svg = this.findD3SvgDom()
  215 + // this.private_up_rect_wrap_svg = this.findD3UpRectWrapSvg()
  216 +
  217 + // 使用外部元素的框架定义图的长宽
  218 + let $jQuery = this.private_jQuery
  219 + this.component_width = $jQuery(this.$el).width() - this.margin_left - this.margin_right
  220 + this.component_height = $jQuery(this.$el).height() - this.margin_top - this.margin_bottom
  221 +
  222 + if (this.useMode === 'child') {
  223 + this.component_width = this.line_chart_outer_div_width - this.margin_left - this.margin_right
  224 + this.component_height = this.line_chart_outer_div_height - this.margin_top - this.margin_bottom
  225 + }
  226 +
  227 + // 开启外部元素长宽监控计数
  228 + /**
  229 + * 开启外部元素长宽监控逻辑(class='line-chart-outer-div')
  230 + * 1、使用模式是alone,并且是编辑模式edit
  231 + * 2、preview预览模式下有条件监控
  232 + */
  233 + if (this.useMode === 'alone' && this.editorMode === 'edit') {
  234 + this.watchWidthHeightTimer.count++
  235 + }
  236 +
  237 + // 刷新线路svg
  238 + this.refreshLineSvg()
  239 + // 刷新下部分线svg
  240 + this.refreshDownLineSvg()
  241 + },
  242 + destroyed () {
  243 + // 组件删除的时候,删除监控定时器
  244 + let timer = this.watchWidthHeightTimer.timer
  245 + if (timer) {
  246 + clearTimeout(timer)
  247 + this.watchWidthHeightTimer.timer = null
  248 + }
  249 + // TODO:其他timer
  250 + },
  251 + watch: {
  252 + 'watchWidthHeightTimer.count' () { // 定时器监控
  253 + let timer = this.watchWidthHeightTimer.timer
  254 + if (timer) {
  255 + clearTimeout(timer)
  256 + this.watchWidthHeightTimer.timer = null
  257 + }
  258 +
  259 + let self = this
  260 + let $jQuery = this.private_jQuery
  261 + self.watchWidthHeightTimer.timer = setTimeout(function () {
  262 + // 处理逻辑
  263 + let width = $jQuery(self.$el).width()
  264 + let height = $jQuery(self.$el).height()
  265 +
  266 + if (width !== self.component_width) {
  267 + self.component_width = width - self.margin_left - self.margin_right
  268 + }
  269 + if (height !== self.component_height) {
  270 + self.component_height = height - self.margin_top - self.margin_bottom
  271 + }
  272 + self.watchWidthHeightTimer.count++
  273 + }, self.watchWidthHeightTimer.millisecond)
  274 + },
  275 + // /**
  276 + // * 当组件作为子组件使用时(useMode=child),line-chart-outer-div样式的div尺寸无法通过编辑器改变(通用样式)
  277 + // * 必须由父组件设定,自组件需要监控改变
  278 + // */
  279 + // line_chart_outer_div_width: function (val) {
  280 + // let self = this
  281 + // if (self.useMode === 'child') {
  282 + // self.component_width = val - self.margin_left - self.margin_right
  283 + // }
  284 + // },
  285 + // line_chart_outer_div_height: function (val) {
  286 + // let self = this
  287 + // if (self.useMode === 'child') {
  288 + // self.component_height = val - self.margin_top - self.margin_bottom
  289 + // }
  290 + // },
  291 + // eBusStopData_child: function (val) {
  292 + // let self = this
  293 + // if (self.useMode === 'child') {
  294 + // self.eBusStopData_child = val
  295 + // }
  296 + // },
  297 + // // ----------- 数据属性 ----------- //
  298 + // eBusStopData: function (currentVal, oldVal) {
  299 + // let self = this
  300 + // if (!Utils.objectEquals(currentVal, oldVal)) {
  301 + // self.refreshLineSvg()
  302 + // }
  303 + // },
  304 + //
  305 + // // ------------ 本身宽高 ----------- //
  306 + // component_width () {
  307 + // this.text_info_width = this.component_width - this.border_size * 2
  308 + // this.line_width = this.component_width - this.border_size * 2
  309 + // },
  310 + // component_height () {
  311 + // this.text_info_height = this.line_info_height + this.arrive_info_height
  312 + // this.line_height = this.component_height - this.text_info_height - this.border_size * 2
  313 + // },
  314 + //
  315 + // svg_width () {
  316 + // this.refreshLineSvg()
  317 + // this.refreshDownLineSvg()
  318 + // },
  319 + // svg_height () {
  320 + // this.refreshLineSvg()
  321 + // this.refreshDownLineSvg()
  322 + // },
  323 + //
  324 + // // ----------- 图外层css 监控 ----------- //
  325 + // margin_left () {
  326 + // let self = this
  327 + // self.component_width = self.component_width - self.margin_left - self.margin_right
  328 + // },
  329 + // margin_right () {
  330 + // let self = this
  331 + // self.component_width = self.component_width - self.margin_left - self.margin_right
  332 + // },
  333 + // margin_top () {
  334 + // let self = this
  335 + // self.component_height = self.component_height - self.margin_top - self.margin_bottom
  336 + // },
  337 + // margin_bottom () {
  338 + // let self = this
  339 + // self.component_height = self.component_height - self.margin_top - self.margin_bottom
  340 + // },
  341 + // border_size () {
  342 + // this.text_info_width = this.component_width - this.border_size * 2
  343 + // this.line_width = this.component_width - this.border_size * 2
  344 + // this.text_info_height = this.line_info_height + this.arrive_info_height
  345 + // this.line_height = this.component_height - this.text_info_height - this.border_size * 2
  346 + //
  347 + // },
  348 + //
  349 + // // ----------- 图内层css 监控 ----------- //
  350 + // // ----------- _flag_5_属性 ----------//
  351 + // chart_left_padding: function () {
  352 + // this.refreshLineSvg()
  353 + // },
  354 + // chart_right_padding: function () {
  355 + // this.refreshLineSvg()
  356 + // },
  357 + // chart_top_padding: function () {
  358 + // this.refreshLineSvg()
  359 + // },
  360 + // chart_up_line_path_s_width: function (val) {
  361 + // let svg = this.private_svg
  362 + // svg.selectAll('g.item path.station_link:not(.down)')
  363 + // .style('stroke-width', val)
  364 + // },
  365 + // chart_up_line_path_s_color: function (val) {
  366 + // let svg = this.private_svg
  367 + // svg.selectAll('g.item path.station_link:not(.down)')
  368 + // .style('stroke', val)
  369 + // },
  370 + // chart_up_line_circle_f_color_current: function (val) {
  371 + // let svg = this.private_svg
  372 + // svg.selectAll('g.item circle.station_circle.current')
  373 + // .style('fill', val)
  374 + // },
  375 + // chart_up_line_circle_f_color_before: function (val) {
  376 + // let svg = this.private_svg
  377 + // svg.selectAll('g.item circle.station_circle.before')
  378 + // .style('fill', val)
  379 + // },
  380 + // chart_up_line_circle_f_color_after: function (val) {
  381 + // let svg = this.private_svg
  382 + // svg.selectAll('g.item circle.station_circle.after')
  383 + // .style('fill', val)
  384 + // },
  385 + // chart_up_line_circle_r: function (val) {
  386 + // let svg = this.private_svg
  387 + // svg.selectAll('g.item circle.station_circle')
  388 + // .style('r', val)
  389 + // },
  390 + // chart_station_text_top_padding: function (val) {
  391 + // this.refreshLineSvg()
  392 + // },
  393 + // chart_station_text_font_size_current: function (val) {
  394 + // let svg = this.private_svg
  395 + // svg.selectAll('g.item text.station_text.up.current')
  396 + // .style('font-size', val)
  397 + // },
  398 + // chart_station_text_font_size_before: function (val) {
  399 + // let svg = this.private_svg
  400 + // svg.selectAll('g.item text.station_text.up.before')
  401 + // .style('font-size', val)
  402 + // },
  403 + // chart_station_text_font_size_after: function (val) {
  404 + // let svg = this.private_svg
  405 + // svg.selectAll('g.item text.station_text.up.after')
  406 + // .style('font-size', val)
  407 + // },
  408 + // chart_station_text_length: function (val) {
  409 + // let svg = this.private_svg
  410 + // svg.selectAll('g.item text')
  411 + // .attr('textLength', val)
  412 + // },
  413 + // chart_up_station_text_font_f_color_current: function (val) {
  414 + // let svg = this.private_svg
  415 + // svg.selectAll('g.item text.station_text.up.current')
  416 + // .style('stroke', val)
  417 + // },
  418 + // chart_up_station_text_font_f_color_before: function (val) {
  419 + // let svg = this.private_svg
  420 + // svg.selectAll('g.item text.station_text.up.before')
  421 + // .style('stroke', val)
  422 + // },
  423 + // chart_up_station_text_font_f_color_after: function (val) {
  424 + // let svg = this.private_svg
  425 + // svg.selectAll('g.item text.station_text.up.after')
  426 + // .style('stroke', val)
  427 + // },
  428 + // // ----------- _flag_6_属性 ----------//
  429 + // down_line_left_padding: function () {
  430 + // this.refreshDownLineSvg()
  431 + // },
  432 + // down_line_right_padding: function () {
  433 + // this.refreshDownLineSvg()
  434 + // },
  435 + // down_line_bottom_padding: function () {
  436 + // this.refreshDownLineSvg()
  437 + // },
  438 + // down_line_s_width: function () {
  439 + // this.refreshDownLineSvg()
  440 + // },
  441 + // down_line_arrow_width: function () {
  442 + // this.refreshDownLineSvg()
  443 + // },
  444 + // down_line_arrow_height: function () {
  445 + // this.refreshDownLineSvg()
  446 + // }
  447 + // ----------- _flag_7_属性 ----------//
  448 + // TODO:
  449 + },
  450 + methods: {
  451 + findD3SvgDom () {
  452 + let $jQuery = this.private_jQuery
  453 + let d3 = this.private_d3
  454 + let svgDom = $jQuery(this.$el).find('svg')[0]
  455 + return d3.select(svgDom)
  456 + },
  457 +
  458 + refreshDownLineSvg () {
  459 + let self = this
  460 +
  461 + let width = self.svg_width // 内部整个svg的宽度
  462 + let height = self.svg_height // 内部整个svg的高度
  463 +
  464 + // 计算svg内部下部分线的属性
  465 + // 5个点,左边两个点作为起点(两个起点用来模拟宽度,如果使用stroke-width,右边箭头无法是夹的),右边3个点组成半个箭头
  466 + // 最左边起点(左下)
  467 + this.down_line_x1 = self.down_line_left_padding
  468 + this.down_line_y1 = height - self.down_line_bottom_padding
  469 + // 最右边箭头起点
  470 + this.down_line_x2 = width - self.down_line_right_padding
  471 + this.down_line_y2 = this.down_line_y1
  472 + // 箭头左上角
  473 + this.down_line_x3 = this.down_line_x2 - self.down_line_arrow_width
  474 + this.down_line_y3 = this.down_line_y2 - self.down_line_arrow_height - self.down_line_s_width
  475 + // 箭头左下角
  476 + this.down_line_x4 = this.down_line_x3
  477 + this.down_line_y4 = this.down_line_y2 - self.down_line_s_width
  478 + // 最左边起点(右下)
  479 + this.down_line_x5 = this.down_line_x1
  480 + this.down_line_y5 = this.down_line_y4
  481 + },
  482 +
  483 + refreshLineSvg () {
  484 + let self = this
  485 +
  486 + // let $jQuery = self.private_jQuery
  487 + let d3 = self.private_d3
  488 +
  489 + let routeData = self.eBusStopData.routeStationDataList
  490 + let width = self.svg_width // 内部整个svg的宽度
  491 + // let height = self.line_height // 内部整个svg的高度
  492 + // let svgNameSpace = self.private_svgns
  493 + let svg = self.private_svg
  494 + let chartLeftPadding = self.chart_left_padding
  495 + let chartRightPadding = self.chart_right_padding
  496 + let chartTopPadding = self.chart_top_padding
  497 + let chartStopNameTopPadding = self.chart_station_text_top_padding
  498 +
  499 + // ------------ 1、添加g元素 ---------- //
  500 + let itemsUpdate = svg.selectAll('g.item')
  501 + .data(routeData, function (d) {
  502 + return d.code
  503 + })
  504 + let itemsEnter = itemsUpdate
  505 + let itemsExit = itemsUpdate.exit()
  506 +
  507 + itemsExit.remove()
  508 + itemsEnter = itemsEnter.enter().append('g').classed('item', true)
  509 +
  510 + // 创建x轴比例尺
  511 + let xScale = d3.scaleLinear()
  512 + .domain([0, routeData.length - 1]) // 定义域
  513 + .range([chartLeftPadding, width - chartRightPadding]) // 值域
  514 +
  515 + // ------------ 2、添加/更新线路图上部分的的path元素 ---------- //
  516 + let upLineFun = d3.line()
  517 + .x(xScale)
  518 + .y(function () {
  519 + return chartTopPadding
  520 + })
  521 + itemsEnter.append('path')
  522 + .classed('station_link', true)
  523 + .style('stroke', self.chart_up_line_path_s_color)
  524 + .style('stroke-width', self.chart_up_line_path_s_width)
  525 + .attr('d', function (d, i) {
  526 + return i < routeData.length - 1 ? upLineFun([i, i + 1]) : ''
  527 + })
  528 + itemsUpdate.select('path')
  529 + .attr('d', function (d, i) {
  530 + return i < routeData.length - 1 ? upLineFun([i, i + 1]) : ''
  531 + })
  532 +
  533 + // ------------ 3、添加/更新线路图上部分的circle元素 ---------- //
  534 + itemsEnter.select(function (d) {
  535 + return d.type !== 1 ? this : null
  536 + }).append('circle')
  537 + .classed('station_circle', true)
  538 + .classed('current', function (d, i) {
  539 + return self.eBusStopData.currentStopStationIndex === i
  540 + })
  541 + .classed('before', function (d, i) {
  542 + return i < self.eBusStopData.currentStopStationIndex
  543 + })
  544 + .classed('after', function (d, i) {
  545 + return i > self.eBusStopData.currentStopStationIndex
  546 + })
  547 + .style('fill', function (d, i) {
  548 + if (i === self.eBusStopData.currentStopStationIndex) {
  549 + return self.chart_up_line_circle_f_color_current
  550 + } else if (i < self.eBusStopData.currentStopStationIndex) {
  551 + return self.chart_up_line_circle_f_color_before
  552 + } else {
  553 + return self.chart_up_line_circle_f_color_after
  554 + }
  555 + })
  556 + .style('stroke-width', 0) // 暂时外部的stroke设置为0,不参与属性设置
  557 + .attr('r', self.chart_up_line_circle_r) // css也设置了,但是有些游览器不支持(如 android5.1的内置游览器),所以直接定义成属性
  558 + .attr('cx', function (d, i) {
  559 + return xScale(i)
  560 + })
  561 + .attr('cy', function () {
  562 + return chartTopPadding
  563 + })
  564 + .attr('data-id', function (d) {
  565 + return d.code
  566 + })
  567 + itemsUpdate.select('circle')
  568 + .attr('cx', function (d, i) {
  569 + return xScale(i)
  570 + })
  571 + .attr('cy', function () {
  572 + return chartTopPadding
  573 + })
  574 +
  575 + // ------------ 4、添加/更新线路图上部分的站点名称text元素 ---------- //
  576 + itemsEnter.append('text')
  577 + .classed('station_text', true)
  578 + .classed('up', true)
  579 + .classed('current', function (d, i) {
  580 + return self.eBusStopData.currentStopStationIndex === i
  581 + })
  582 + .classed('before', function (d, i) {
  583 + return i < self.eBusStopData.currentStopStationIndex
  584 + })
  585 + .classed('after', function (d, i) {
  586 + return i > self.eBusStopData.currentStopStationIndex
  587 + })
  588 + .style('font-size', function (d, i) {
  589 + if (i === self.eBusStopData.currentStopStationIndex) {
  590 + return self.chart_station_text_font_size_current + 'px'
  591 + } else if (i < self.eBusStopData.currentStopStationIndex) {
  592 + return self.chart_station_text_font_size_before + 'px'
  593 + } else {
  594 + return self.chart_station_text_font_size_after + 'px'
  595 + }
  596 + })
  597 + .style('stroke', function (d, i) {
  598 + if (i === self.eBusStopData.currentStopStationIndex) {
  599 + return self.chart_up_station_text_font_f_color_current
  600 + } else if (i < self.eBusStopData.currentStopStationIndex) {
  601 + return self.chart_up_station_text_font_f_color_before
  602 + } else {
  603 + return self.chart_up_station_text_font_f_color_after
  604 + }
  605 + })
  606 + .attr('textLength', self.chart_station_text_length)
  607 + .text(function (d) {
  608 + if (!d.name) {
  609 + return 0
  610 + }
  611 + return d.name
  612 + })
  613 + .attr('title', function (d) {
  614 + return d.name
  615 + })
  616 + .attr('x', function (d, i) {
  617 + return xScale(i)
  618 + })
  619 + .attr('y', function (d) {
  620 + return chartStopNameTopPadding
  621 + })
  622 + itemsUpdate.select('text.station_text')
  623 + .classed('up', true)
  624 + .text(function (d) {
  625 + if (!d.name) {
  626 + return 0
  627 + }
  628 + return d.name
  629 + })
  630 + .attr('title', function (d) {
  631 + return d.name
  632 + })
  633 + .attr('x', function (d, i) {
  634 + return xScale(i)
  635 + })
  636 + .attr('y', function (d) {
  637 + return chartStopNameTopPadding
  638 + })
  639 + }
  640 + }
  641 +
  642 +}
  643 +
  644 +
  645 +
  646 +
  647 +
  648 +
  649 +
... ...
front-end/h5/src/components/core/plugins/bsth/othergj/linechart/chart/css/othergj-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 +.othergj-eBusStop-line-chart-outer-div, .othergj-eBusStop-line-chart-outer-div * {
  9 + box-sizing: border-box;
  10 +}
  11 +
  12 +/**
  13 + 电子站牌线路模拟图使用的css
  14 + */
  15 +svg.othergj-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.othergj-eBusStop-line-chart path.station_link {
  35 + stroke-width: 3.5;
  36 + stroke: #5E96D2;
  37 + Pointer-events: none;
  38 +}
  39 +
  40 +svg.othergj-eBusStop-line-chart circle.station_circle {
  41 + fill: #5e96d2;
  42 + /*r: 5.5;*/
  43 + stroke: rgb(253, 253, 253);
  44 + stroke-width: 3;
  45 + Pointer-events: none;
  46 +}
  47 +
  48 +svg.othergj-eBusStop-line-chart text.station_text {
  49 + writing-mode: tb;
  50 + fill: #3e3e3e;
  51 + letter-spacing: -.2px;
  52 + text-shadow: 0 0 2px #dadada;
  53 + Pointer-events: none;
  54 +}
  55 +
  56 +svg.othergj-eBusStop-line-chart text.station_text.up {
  57 + fill: #4556b6;
  58 +}
  59 +
  60 +
  61 +
... ...
front-end/h5/src/components/core/plugins/bsth/othergj/linechart/chart/models/eBusStopData.js 0 → 100644
  1 +/**
  2 + * 公交线路模拟图组件用数据。
  3 + */
  4 +
  5 +// 站点信息
  6 +class StationData {
  7 + /**
  8 + * 构造函数。
  9 + * @param name 站点名字
  10 + * @param code 站点编码
  11 + */
  12 + constructor (name, code) {
  13 + this._name = name
  14 + this._code = code
  15 + }
  16 +
  17 + get name () {
  18 + return this._name
  19 + }
  20 + get code () {
  21 + return this._code
  22 + }
  23 +}
  24 +// 路由信息
  25 +class RouteData {
  26 + /**
  27 + * 构造函数。
  28 + * @param stopStationIndex 当前站牌对应站点索引
  29 + * @param stationDataList 所有站点列表(StationData类型)
  30 + */
  31 + constructor (stopStationIndex, stationDataList = []) {
  32 + this._stopStationIndex = stopStationIndex
  33 + this._stationDataList = [...stationDataList]
  34 + }
  35 +
  36 + get index () {
  37 + return this._stopStationIndex
  38 + }
  39 + get dataList () {
  40 + return this._stationDataList
  41 + }
  42 +}
  43 +
  44 +// 电子站牌信息
  45 +class EBusStopData {
  46 + /**
  47 + * 构造函数。
  48 + * @param lineName 线路名称
  49 + * @param lineCode 线路编码
  50 + * @param routeData 路由信息(RouteData类型)
  51 + * @param startTime 首班车时间字符串(格式: HH:mm)
  52 + * @param endTime 末班车时间字符串(格式:HH:mm)
  53 + */
  54 + constructor (lineName, lineCode, routeData, startTime = '00:00', endTime = '23:59') {
  55 + this._lineName = lineName
  56 + this._lineCode = lineCode
  57 + this._routeData = routeData
  58 + this._startTime = startTime
  59 + this._endTime = endTime
  60 + }
  61 +
  62 + /**
  63 + * 获取线路名称。
  64 + * @return {*}
  65 + */
  66 + get lineName () {
  67 + return this._lineName
  68 + }
  69 + /**
  70 + * 获取线路编码。
  71 + * @return {*}
  72 + */
  73 + get lineCode () {
  74 + return this._lineCode
  75 + }
  76 + /**
  77 + * 获取路由站点列表。
  78 + */
  79 + get routeStationDataList () {
  80 + return this._routeData.dataList
  81 + }
  82 + /**
  83 + * 获取当前站点在路由中的索引。
  84 + */
  85 + get currentStopStationIndex () {
  86 + return this._routeData.index
  87 + }
  88 + /**
  89 + * 获取当前路由的终点站。
  90 + * @return {string}
  91 + */
  92 + get endStationName () {
  93 + if (this._routeData.dataList.length > 0) {
  94 + return this._routeData.dataList.slice(-1)[0].name
  95 + } else {
  96 + return ''
  97 + }
  98 + }
  99 +
  100 + /**
  101 + * 获取首班车时间。
  102 + */
  103 + get startTime () {
  104 + return this._startTime
  105 + }
  106 +
  107 + /**
  108 + * 获取末班车时间。
  109 + */
  110 + get endTime () {
  111 + return this._endTime
  112 + }
  113 +
  114 + /**
  115 + * 产生测试数据。
  116 + */
  117 + static generateTestData () {
  118 + // 1、站点信息
  119 + let s1 = new StationData('站点1', '1')
  120 + let s2 = new StationData('站点2', '2')
  121 + let s3 = new StationData('站点3', '3')
  122 + let s4 = new StationData('站点4', '4')
  123 + let s5 = new StationData('站点5', '5')
  124 + let s6 = new StationData('站点6', '6')
  125 + let stationDataList = [s1, s2, s3, s4, s5, s6]
  126 + // 2、路由信息
  127 + let routeData = new RouteData(2, stationDataList)
  128 + // 3、电子站牌信息
  129 + return new EBusStopData('线路1', '1', routeData)
  130 + }
  131 +
  132 + /**
  133 + * 产生空测试数据。
  134 + */
  135 + static generateTestData_null () {
  136 + return new EBusStopData('', '', new RouteData(0, []))
  137 + }
  138 +
  139 +}
  140 +
  141 +export {
  142 + StationData,
  143 + RouteData,
  144 + EBusStopData
  145 +}
... ...
front-end/h5/src/components/core/plugins/bsth/othergj/linechart/chart/othergj-eBusStop-line-chart.js 0 → 100644
  1 +/**
  2 + * 自定义线路模拟图组件(临港公交电子站牌使用)
  3 + */
  4 +import PropTypes from '@luban-h5/plugin-common-props'
  5 +
  6 +import Utils from 'core/plugins/bsth/bsth-utils'
  7 +import { EBusStopData } from 'core/plugins/bsth/othergj/linechart/chart/models/eBusStopData'
  8 +
  9 +import './css/othergj-eBusStop-line-chart.css'
  10 +
  11 +import moment from 'moment'
  12 +
  13 +export default {
  14 + extra: {
  15 + defaultStyle: { // 默认属性
  16 + top: 0,
  17 + left: 0,
  18 + width: 700,
  19 + height: 230
  20 + }
  21 + },
  22 + name: 'othergj-eBusStop-line-chart',
  23 + data () {
  24 + this.private_svgns = 'http://www.w3.org/2000/svg' // svg元素名字空间
  25 + this.private_svg = null // 创建的根svg元素,由mounted钩子函数创建
  26 + // this.private_up_rect_wrap_svg = null // 创建包含矩形最外层g元素
  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 + svg_width: 350, // 图宽度
  51 + svg_height: 300, // 图高度
  52 +
  53 + // TODO:其他属性
  54 +
  55 + // svg内部下部分线的属性(mounted初始计算一次)
  56 + down_line_x1: 0,
  57 + down_line_y1: 0,
  58 + down_line_x2: 0,
  59 + down_line_y2: 0,
  60 + down_line_x3: 0,
  61 + down_line_y3: 0,
  62 + down_line_x4: 0,
  63 + down_line_y4: 0,
  64 + down_line_x5: 0,
  65 + down_line_y5: 0,
  66 +
  67 + eBusStopData: null // 电子站牌数据(EBusStopData类型)
  68 + }
  69 + },
  70 + computed: {
  71 + // TODO:
  72 + },
  73 + props: {
  74 + useMode: PropTypes.string({ // 自定义使用模式,alone:(单独使用),child:(子组件)
  75 + defaultValue: 'alone',
  76 + label: '使用模式',
  77 + visible: false
  78 + }),
  79 + editorMode: PropTypes.string({ // 编辑模式会由编辑器自动注入(值:edit, preview)
  80 + defaultValue: 'edit',
  81 + label: '模式',
  82 + visible: false
  83 + }),
  84 + line_chart_outer_div_width: PropTypes.number({
  85 + defaultValue: 350,
  86 + label: 'line-chart-outer-div样式的div宽度',
  87 + visible: false
  88 + }),
  89 + line_chart_outer_div_height: PropTypes.number({
  90 + defaultValue: 300,
  91 + label: 'line-chart-outer-div样式的div高度',
  92 + visible: false
  93 + }),
  94 + eBusStopData_child: { // 作为子组件,父对象传值
  95 + type: EBusStopData,
  96 + default: function () {
  97 + return null
  98 + }
  99 + },
  100 +
  101 + // 数据属性
  102 + _flag_1_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="数据属性" class="bsth-line-item-divider"></hr>) } }),
  103 + // 图外层css
  104 + _flag_2_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图外层css属性" class="bsth-line-item-divider"></hr>) } }),
  105 + margin_left: PropTypes.number({ label: '图左边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  106 + margin_right: PropTypes.number({ label: '图右边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  107 + margin_top: PropTypes.number({ label: '图上边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  108 + margin_bottom: PropTypes.number({ label: '图底部margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  109 + border_size: PropTypes.number({ label: '图边框宽度', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  110 + background_color: PropTypes.color({ label: '背景颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  111 + // 图内层css
  112 + _flag_5_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层线路图css属性" class="bsth-line-item-divider"></hr>) } }),
  113 + svg_background: PropTypes.color({ label: '线路图背景颜色', defaultValue: '#9EE0DF', layout: { prefixCls: 'bsth-line' } }),
  114 + chart_left_padding: PropTypes.number({ label: '内部线路图距离左边', defaultValue: 50, layout: { prefixCls: 'bsth-line' } }),
  115 + chart_right_padding: PropTypes.number({ label: '内部线路图距离右边', defaultValue: 50, layout: { prefixCls: 'bsth-line' } }),
  116 + chart_top_padding: PropTypes.number({ label: '内部线路图距离上边', defaultValue: 13, layout: { prefixCls: 'bsth-line' } }),
  117 + chart_up_line_path_s_width: PropTypes.number({ label: '上部分线宽度', defaultValue: 5, layout: { prefixCls: 'bsth-line' } }),
  118 + chart_up_line_path_s_color: PropTypes.color({ label: '上部分线颜色', defaultValue: '#008000', layout: { prefixCls: 'bsth-line' } }),
  119 + chart_up_line_circle_f_color_current: PropTypes.color({ label: '线圆圈填充色-当前站点', defaultValue: '#CB0808', layout: { prefixCls: 'bsth-line' } }),
  120 + chart_up_line_circle_f_color_before: PropTypes.color({ label: '线圆圈填充色-前面站点', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  121 + chart_up_line_circle_f_color_after: PropTypes.color({ label: '线圆圈填充色-后面站点', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  122 + chart_up_line_circle_r: PropTypes.number({ label: '线圆圈大小', defaultValue: 8, layout: { prefixCls: 'bsth-line' } }),
  123 + chart_station_text_top_padding: PropTypes.number({ label: '站点文字距离上边', defaultValue: 30, layout: { prefixCls: 'bsth-line' } }),
  124 + chart_station_text_font_size_current: PropTypes.number({ label: '站名字体大小-当前站点', defaultValue: 25, layout: { prefixCls: 'bsth-line' } }),
  125 + chart_station_text_font_size_before: PropTypes.number({ label: '站名字体大小-前面站点', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  126 + chart_station_text_font_size_after: PropTypes.number({ label: '站名字体大小-后面站点', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  127 + chart_station_text_length: PropTypes.number({ label: '站名长度', defaultValue: 100, layout: { prefixCls: 'bsth-line' } }),
  128 + chart_up_station_text_font_f_color_current: PropTypes.color({ label: '站名颜色-当前站点', defaultValue: '#060D37', layout: { prefixCls: 'bsth-line' } }),
  129 + chart_up_station_text_font_f_color_before: PropTypes.color({ label: '站名颜色-前面站点', defaultValue: '#9398B4', layout: { prefixCls: 'bsth-line' } }),
  130 + chart_up_station_text_font_f_color_after: PropTypes.color({ label: '站名颜色-后面站点', defaultValue: '#4556b6', layout: { prefixCls: 'bsth-line' } }),
  131 + _flag_6_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层下部分线css属性" class="bsth-line-item-divider"></hr>) } }),
  132 + down_line_left_padding: PropTypes.number({ label: '线距离左边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  133 + down_line_right_padding: PropTypes.number({ label: '线距离右边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  134 + down_line_bottom_padding: PropTypes.number({ label: '线距离下边', defaultValue: 6, layout: { prefixCls: 'bsth-line' } }),
  135 + down_line_s_width: PropTypes.number({ label: '线宽度', defaultValue: 5, layout: { prefixCls: 'bsth-line' } }),
  136 + down_line_s_color: PropTypes.color({ label: '线颜色', defaultValue: '#277461', layout: { prefixCls: 'bsth-line' } }),
  137 + down_line_arrow_width: PropTypes.number({ label: '箭头宽度', defaultValue: 55, layout: { prefixCls: 'bsth-line' } }),
  138 + down_line_arrow_height: PropTypes.number({ label: '箭头高度', defaultValue: 15, layout: { prefixCls: 'bsth-line' } }),
  139 + _flag_7_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="无数据提示css属性" class="bsth-line-item-divider"></hr>) } }),
  140 + empty_info_font_size: PropTypes.number({ label: '无数据提示文字字体大小', defaultValue: 30, layout: { prefixCls: 'bsth-line' } }),
  141 + empty_info_font_color: PropTypes.color({ label: '无数据提示文字字体颜色', defaultValue: '#000000', layout: { prefixCls: 'bsth-line' } }),
  142 + empty_info_top_padding: PropTypes.number({ label: '无数据提示文字距离上边', defaultValue: 25, layout: { prefixCls: 'bsth-line' } })
  143 + },
  144 +
  145 + render () {
  146 + const innerDivStyle = {
  147 + 'width': this.component_width + 'px',
  148 + 'height': this.component_height + 'px',
  149 + 'border': this.border_size + 'px solid black',
  150 + 'margin-left': this.margin_left + 'px',
  151 + 'margin-right': this.margin_right + 'px',
  152 + 'margin-top': this.margin_top + 'px',
  153 + 'margin-bottom': this.margin_bottom + 'px',
  154 + 'background': this.background_color,
  155 + 'position': 'relative'
  156 + }
  157 +
  158 + const downLinePathD =
  159 + 'M' + this.down_line_x1 + ' ' + this.down_line_y1 + ' ' +
  160 + 'L' + this.down_line_x2 + ' ' + this.down_line_y2 + ' ' +
  161 + 'L' + this.down_line_x3 + ' ' + this.down_line_y3 + ' ' +
  162 + 'L' + this.down_line_x4 + ' ' + this.down_line_y4 + ' ' +
  163 + 'L' + this.down_line_x5 + ' ' + this.down_line_y5 + ' ' +
  164 + 'Z'
  165 +
  166 + const svgStyle = {
  167 + // 'width': this.svg_width + 'px',
  168 + 'height': this.svg_height + 'px',
  169 + 'background-color': this.svg_background
  170 + }
  171 +
  172 + const emptyInfoStyle = {
  173 + 'height': '44px',
  174 + 'position': 'absolute',
  175 + 'left': '50%',
  176 + 'transform': 'translate(-50%, 0)',
  177 + '-webkit-transform': 'translate(-50%, 0)',
  178 + 'color': this.empty_info_font_color,
  179 + 'font-size': this.empty_info_font_size + 'px',
  180 + 'padding-top': this.empty_info_top_padding + 'px',
  181 + // 'font-family': 'Open Sans, sans-serif',
  182 + 'font-weight': 'bold'
  183 + }
  184 +
  185 + /* 最外层div对应编辑器的通用样式 */
  186 + return (
  187 + <div class="othergj-eBusStop-line-chart-outer-div">
  188 + <div style={innerDivStyle}>
  189 + <svg class="othergj-eBusStop-line-chart"
  190 + data-code={this.eBusStopData.lineCode}
  191 + style={svgStyle}>
  192 + <g class="arrow-wrap">
  193 + <path d={downLinePathD} style={{ 'fill': this.down_line_s_color }}></path>
  194 + </g>
  195 + </svg>
  196 + {
  197 + this.eBusStopData.routeStationDataList.length === 0 ? (<div style={emptyInfoStyle}>线路未开通,系统调试中</div>) : ''
  198 + }
  199 +
  200 + </div>
  201 + </div>
  202 + )
  203 + },
  204 + beforeMount () {
  205 + // 设置数据
  206 + if (this.useMode === 'alone') { // 单独使用,使用测试数据
  207 + this.eBusStopData = EBusStopData.generateTestData()
  208 + } else { // 自组件使用,使用父组件传值
  209 + this.eBusStopData = this.eBusStopData_child
  210 + }
  211 + },
  212 + mounted () {
  213 + // svg元素
  214 + this.private_svg = this.findD3SvgDom()
  215 + // this.private_up_rect_wrap_svg = this.findD3UpRectWrapSvg()
  216 +
  217 + // 使用外部元素的框架定义图的长宽
  218 + let $jQuery = this.private_jQuery
  219 + this.component_width = $jQuery(this.$el).width() - this.margin_left - this.margin_right
  220 + this.component_height = $jQuery(this.$el).height() - this.margin_top - this.margin_bottom
  221 +
  222 + if (this.useMode === 'child') {
  223 + this.component_width = this.line_chart_outer_div_width - this.margin_left - this.margin_right
  224 + this.component_height = this.line_chart_outer_div_height - this.margin_top - this.margin_bottom
  225 + }
  226 +
  227 + // 开启外部元素长宽监控计数
  228 + /**
  229 + * 开启外部元素长宽监控逻辑(class='line-chart-outer-div')
  230 + * 1、使用模式是alone,并且是编辑模式edit
  231 + * 2、preview预览模式下有条件监控
  232 + */
  233 + if (this.useMode === 'alone' && this.editorMode === 'edit') {
  234 + this.watchWidthHeightTimer.count++
  235 + }
  236 +
  237 + // 刷新线路svg
  238 + this.refreshLineSvg()
  239 + // 刷新下部分线svg
  240 + this.refreshDownLineSvg()
  241 + },
  242 + destroyed () {
  243 + // 组件删除的时候,删除监控定时器
  244 + let timer = this.watchWidthHeightTimer.timer
  245 + if (timer) {
  246 + clearTimeout(timer)
  247 + this.watchWidthHeightTimer.timer = null
  248 + }
  249 + // TODO:其他timer
  250 + },
  251 + watch: {
  252 + 'watchWidthHeightTimer.count' () { // 定时器监控
  253 + let timer = this.watchWidthHeightTimer.timer
  254 + if (timer) {
  255 + clearTimeout(timer)
  256 + this.watchWidthHeightTimer.timer = null
  257 + }
  258 +
  259 + let self = this
  260 + let $jQuery = this.private_jQuery
  261 + self.watchWidthHeightTimer.timer = setTimeout(function () {
  262 + // 处理逻辑
  263 + let width = $jQuery(self.$el).width()
  264 + let height = $jQuery(self.$el).height()
  265 +
  266 + if (width !== self.component_width) {
  267 + self.component_width = width - self.margin_left - self.margin_right
  268 + }
  269 + if (height !== self.component_height) {
  270 + self.component_height = height - self.margin_top - self.margin_bottom
  271 + }
  272 + self.watchWidthHeightTimer.count++
  273 + }, self.watchWidthHeightTimer.millisecond)
  274 + },
  275 + /**
  276 + * 当组件作为子组件使用时(useMode=child),line-chart-outer-div样式的div尺寸无法通过编辑器改变(通用样式)
  277 + * 必须由父组件设定,自组件需要监控改变
  278 + */
  279 + line_chart_outer_div_width: function (val) {
  280 + let self = this
  281 + if (self.useMode === 'child') {
  282 + self.component_width = val - self.margin_left - self.margin_right
  283 + }
  284 + },
  285 + line_chart_outer_div_height: function (val) {
  286 + let self = this
  287 + if (self.useMode === 'child') {
  288 + self.component_height = val - self.margin_top - self.margin_bottom
  289 + }
  290 + },
  291 + eBusStopData_child: function (val) {
  292 + let self = this
  293 + if (self.useMode === 'child') {
  294 + self.eBusStopData_child = val
  295 + }
  296 + },
  297 + // ----------- 数据属性 ----------- //
  298 + eBusStopData: function (currentVal, oldVal) {
  299 + let self = this
  300 + if (!Utils.objectEquals(currentVal, oldVal)) {
  301 + self.refreshLineSvg()
  302 + }
  303 + },
  304 + // ------------ 本身宽高 ----------- //
  305 + component_width () {
  306 + this.svg_width = this.component_width - this.border_size * 2
  307 + },
  308 + component_height () {
  309 + this.svg_height = this.component_height - this.border_size * 2
  310 + },
  311 +
  312 + svg_width () {
  313 + this.refreshLineSvg()
  314 + this.refreshDownLineSvg()
  315 + },
  316 + svg_height () {
  317 + this.refreshLineSvg()
  318 + this.refreshDownLineSvg()
  319 + },
  320 + // ----------- 图外层css 监控 ----------- //
  321 + margin_left () {
  322 + let self = this
  323 + self.component_width = self.component_width - self.margin_left - self.margin_right
  324 + },
  325 + margin_right () {
  326 + let self = this
  327 + self.component_width = self.component_width - self.margin_left - self.margin_right
  328 + },
  329 + margin_top () {
  330 + let self = this
  331 + self.component_height = self.component_height - self.margin_top - self.margin_bottom
  332 + },
  333 + margin_bottom () {
  334 + let self = this
  335 + self.component_height = self.component_height - self.margin_top - self.margin_bottom
  336 + },
  337 + border_size () {
  338 + this.svg_width = this.component_width - this.border_size * 2
  339 + this.svg_height = this.component_height - this.text_info_height - this.border_size * 2
  340 +
  341 + },
  342 +
  343 + // ----------- 图内层css 监控 ----------- //
  344 + // ----------- _flag_5_属性 -------------//
  345 + chart_left_padding: function () {
  346 + this.refreshLineSvg()
  347 + },
  348 + chart_right_padding: function () {
  349 + this.refreshLineSvg()
  350 + },
  351 + chart_top_padding: function () {
  352 + this.refreshLineSvg()
  353 + },
  354 + chart_up_line_path_s_width: function (val) {
  355 + let svg = this.private_svg
  356 + svg.selectAll('g.item path.station_link:not(.down)')
  357 + .style('stroke-width', val)
  358 + },
  359 + chart_up_line_path_s_color: function (val) {
  360 + let svg = this.private_svg
  361 + svg.selectAll('g.item path.station_link:not(.down)')
  362 + .style('stroke', val)
  363 + },
  364 + chart_up_line_circle_f_color_current: function (val) {
  365 + let svg = this.private_svg
  366 + svg.selectAll('g.item circle.station_circle.current')
  367 + .style('fill', val)
  368 + },
  369 + chart_up_line_circle_f_color_before: function (val) {
  370 + let svg = this.private_svg
  371 + svg.selectAll('g.item circle.station_circle.before')
  372 + .style('fill', val)
  373 + },
  374 + chart_up_line_circle_f_color_after: function (val) {
  375 + let svg = this.private_svg
  376 + svg.selectAll('g.item circle.station_circle.after')
  377 + .style('fill', val)
  378 + },
  379 + chart_up_line_circle_r: function (val) {
  380 + let svg = this.private_svg
  381 + svg.selectAll('g.item circle.station_circle')
  382 + .style('r', val)
  383 + },
  384 + chart_station_text_top_padding: function (val) {
  385 + this.refreshLineSvg()
  386 + },
  387 + chart_station_text_font_size_current: function (val) {
  388 + let svg = this.private_svg
  389 + svg.selectAll('g.item text.station_text.up.current')
  390 + .style('font-size', val)
  391 + },
  392 + chart_station_text_font_size_before: function (val) {
  393 + let svg = this.private_svg
  394 + svg.selectAll('g.item text.station_text.up.before')
  395 + .style('font-size', val)
  396 + },
  397 + chart_station_text_font_size_after: function (val) {
  398 + let svg = this.private_svg
  399 + svg.selectAll('g.item text.station_text.up.after')
  400 + .style('font-size', val)
  401 + },
  402 + chart_station_text_length: function (val) {
  403 + let svg = this.private_svg
  404 + svg.selectAll('g.item text')
  405 + .attr('textLength', val)
  406 + },
  407 + chart_up_station_text_font_f_color_current: function (val) {
  408 + let svg = this.private_svg
  409 + svg.selectAll('g.item text.station_text.up.current')
  410 + .style('stroke', val)
  411 + },
  412 + chart_up_station_text_font_f_color_before: function (val) {
  413 + let svg = this.private_svg
  414 + svg.selectAll('g.item text.station_text.up.before')
  415 + .style('stroke', val)
  416 + },
  417 + chart_up_station_text_font_f_color_after: function (val) {
  418 + let svg = this.private_svg
  419 + svg.selectAll('g.item text.station_text.up.after')
  420 + .style('stroke', val)
  421 + },
  422 + // ----------- _flag_6_属性 ------------- //
  423 + down_line_left_padding: function () {
  424 + this.refreshDownLineSvg()
  425 + },
  426 + down_line_right_padding: function () {
  427 + this.refreshDownLineSvg()
  428 + },
  429 + down_line_bottom_padding: function () {
  430 + this.refreshDownLineSvg()
  431 + },
  432 + down_line_s_width: function () {
  433 + this.refreshDownLineSvg()
  434 + },
  435 + down_line_arrow_width: function () {
  436 + this.refreshDownLineSvg()
  437 + },
  438 + down_line_arrow_height: function () {
  439 + this.refreshDownLineSvg()
  440 + }
  441 + // ----------- _flag_7_属性 ------------- //
  442 + // TODO:
  443 + },
  444 + methods: {
  445 + findD3SvgDom () {
  446 + let $jQuery = this.private_jQuery
  447 + let d3 = this.private_d3
  448 + let svgDom = $jQuery(this.$el).find('svg')[0]
  449 + return d3.select(svgDom)
  450 + },
  451 + refreshDownLineSvg () {
  452 + let self = this
  453 +
  454 + let width = self.svg_width // 内部整个svg的宽度
  455 + let height = self.svg_height // 内部整个svg的高度
  456 +
  457 + // 计算svg内部下部分线的属性
  458 + // 5个点,左边两个点作为起点(两个起点用来模拟宽度,如果使用stroke-width,右边箭头无法是夹的),右边3个点组成半个箭头
  459 + // 最左边起点(左下)
  460 + this.down_line_x1 = self.down_line_left_padding
  461 + this.down_line_y1 = height - self.down_line_bottom_padding
  462 + // 最右边箭头起点
  463 + this.down_line_x2 = width - self.down_line_right_padding
  464 + this.down_line_y2 = this.down_line_y1
  465 + // 箭头左上角
  466 + this.down_line_x3 = this.down_line_x2 - self.down_line_arrow_width
  467 + this.down_line_y3 = this.down_line_y2 - self.down_line_arrow_height - self.down_line_s_width
  468 + // 箭头左下角
  469 + this.down_line_x4 = this.down_line_x3
  470 + this.down_line_y4 = this.down_line_y2 - self.down_line_s_width
  471 + // 最左边起点(右下)
  472 + this.down_line_x5 = this.down_line_x1
  473 + this.down_line_y5 = this.down_line_y4
  474 + },
  475 + refreshLineSvg () {
  476 + let self = this
  477 +
  478 + // let $jQuery = self.private_jQuery
  479 + let d3 = self.private_d3
  480 +
  481 + let routeData = self.eBusStopData.routeStationDataList
  482 + let width = self.svg_width // 内部整个svg的宽度
  483 + // let height = self.svg_height // 内部整个svg的高度
  484 + // let svgNameSpace = self.private_svgns
  485 + let svg = self.private_svg
  486 + let chartLeftPadding = self.chart_left_padding
  487 + let chartRightPadding = self.chart_right_padding
  488 + let chartTopPadding = self.chart_top_padding
  489 + let chartStopNameTopPadding = self.chart_station_text_top_padding
  490 +
  491 + // ------------ 1、添加g元素 ---------- //
  492 + let itemsUpdate = svg.selectAll('g.item')
  493 + .data(routeData, function (d) {
  494 + return d.code
  495 + })
  496 + let itemsEnter = itemsUpdate
  497 + let itemsExit = itemsUpdate.exit()
  498 +
  499 + itemsExit.remove()
  500 + itemsEnter = itemsEnter.enter().append('g').classed('item', true)
  501 +
  502 + // 创建x轴比例尺
  503 + let xScale = d3.scaleLinear()
  504 + .domain([0, routeData.length - 1]) // 定义域
  505 + .range([chartLeftPadding, width - chartRightPadding]) // 值域
  506 +
  507 + // ------------ 2、添加/更新线路图上部分的的path元素 ---------- //
  508 + let upLineFun = d3.line()
  509 + .x(xScale)
  510 + .y(function () {
  511 + return chartTopPadding
  512 + })
  513 + itemsEnter.append('path')
  514 + .classed('station_link', true)
  515 + .style('stroke', self.chart_up_line_path_s_color)
  516 + .style('stroke-width', self.chart_up_line_path_s_width)
  517 + .attr('d', function (d, i) {
  518 + return i < routeData.length - 1 ? upLineFun([i, i + 1]) : ''
  519 + })
  520 + itemsUpdate.select('path')
  521 + .attr('d', function (d, i) {
  522 + return i < routeData.length - 1 ? upLineFun([i, i + 1]) : ''
  523 + })
  524 +
  525 + // ------------ 3、添加/更新线路图上部分的circle元素 ---------- //
  526 + itemsEnter.select(function (d) {
  527 + return d.type !== 1 ? this : null
  528 + }).append('circle')
  529 + .classed('station_circle', true)
  530 + .classed('current', function (d, i) {
  531 + return self.eBusStopData.currentStopStationIndex === i
  532 + })
  533 + .classed('before', function (d, i) {
  534 + return i < self.eBusStopData.currentStopStationIndex
  535 + })
  536 + .classed('after', function (d, i) {
  537 + return i > self.eBusStopData.currentStopStationIndex
  538 + })
  539 + .style('fill', function (d, i) {
  540 + if (i === self.eBusStopData.currentStopStationIndex) {
  541 + return self.chart_up_line_circle_f_color_current
  542 + } else if (i < self.eBusStopData.currentStopStationIndex) {
  543 + return self.chart_up_line_circle_f_color_before
  544 + } else {
  545 + return self.chart_up_line_circle_f_color_after
  546 + }
  547 + })
  548 + .style('stroke-width', 0) // 暂时外部的stroke设置为0,不参与属性设置
  549 + .attr('r', self.chart_up_line_circle_r) // css也设置了,但是有些游览器不支持(如 android5.1的内置游览器),所以直接定义成属性
  550 + .attr('cx', function (d, i) {
  551 + return xScale(i)
  552 + })
  553 + .attr('cy', function () {
  554 + return chartTopPadding
  555 + })
  556 + .attr('data-id', function (d) {
  557 + return d.code
  558 + })
  559 + itemsUpdate.select('circle')
  560 + .attr('cx', function (d, i) {
  561 + return xScale(i)
  562 + })
  563 + .attr('cy', function () {
  564 + return chartTopPadding
  565 + })
  566 +
  567 + // ------------ 4、添加/更新线路图上部分的站点名称text元素 ---------- //
  568 + itemsEnter.append('text')
  569 + .classed('station_text', true)
  570 + .classed('up', true)
  571 + .classed('current', function (d, i) {
  572 + return self.eBusStopData.currentStopStationIndex === i
  573 + })
  574 + .classed('before', function (d, i) {
  575 + return i < self.eBusStopData.currentStopStationIndex
  576 + })
  577 + .classed('after', function (d, i) {
  578 + return i > self.eBusStopData.currentStopStationIndex
  579 + })
  580 + .style('font-size', function (d, i) {
  581 + if (i === self.eBusStopData.currentStopStationIndex) {
  582 + return self.chart_station_text_font_size_current + 'px'
  583 + } else if (i < self.eBusStopData.currentStopStationIndex) {
  584 + return self.chart_station_text_font_size_before + 'px'
  585 + } else {
  586 + return self.chart_station_text_font_size_after + 'px'
  587 + }
  588 + })
  589 + .style('stroke', function (d, i) {
  590 + if (i === self.eBusStopData.currentStopStationIndex) {
  591 + return self.chart_up_station_text_font_f_color_current
  592 + } else if (i < self.eBusStopData.currentStopStationIndex) {
  593 + return self.chart_up_station_text_font_f_color_before
  594 + } else {
  595 + return self.chart_up_station_text_font_f_color_after
  596 + }
  597 + })
  598 + .attr('textLength', self.chart_station_text_length)
  599 + .text(function (d) {
  600 + if (!d.name) {
  601 + return 0
  602 + }
  603 + return d.name
  604 + })
  605 + .attr('title', function (d) {
  606 + return d.name
  607 + })
  608 + .attr('x', function (d, i) {
  609 + return xScale(i)
  610 + })
  611 + .attr('y', function (d) {
  612 + return chartStopNameTopPadding
  613 + })
  614 + itemsUpdate.select('text.station_text')
  615 + .classed('up', true)
  616 + .text(function (d) {
  617 + if (!d.name) {
  618 + return 0
  619 + }
  620 + return d.name
  621 + })
  622 + .attr('title', function (d) {
  623 + return d.name
  624 + })
  625 + .attr('x', function (d, i) {
  626 + return xScale(i)
  627 + })
  628 + .attr('y', function (d) {
  629 + return chartStopNameTopPadding
  630 + })
  631 + }
  632 + }
  633 +}
... ...
front-end/h5/src/components/core/plugins/index.js
... ... @@ -33,6 +33,8 @@ import EBusStopLineChartList from &#39;core/plugins/bsth/lggj/list/eBusStop-line-cha
33 33 import MhgjEBusStopLineChart from 'core/plugins/bsth/mhgj/chart/mhgj-eBusStop-line-chart'
34 34 import MhgjEBusStopLineChartList from 'core/plugins/bsth/mhgj/list/mhgj-eBusStop-line-chart-list'
35 35  
  36 +import OthergjEBusStopLineChart from 'core/plugins/bsth/othergj/linechart/chart/othergj-eBusStop-line-chart'
  37 +
36 38 export const pluginsList = [
37 39 // {
38 40 // i18nTitle: {
... ... @@ -351,7 +353,7 @@ export const pluginsList = [
351 353 title: '电子站牌单线路模拟图2',
352 354 icon: 'list',
353 355 component: MhgjEBusStopLineChart,
354   - visible: true,
  356 + visible: false,
355 357 name: MhgjEBusStopLineChart.name
356 358 },
357 359  
... ... @@ -367,6 +369,19 @@ export const pluginsList = [
367 369 name: MhgjEBusStopLineChartList.name
368 370 },
369 371  
  372 + {
  373 + i18nTitle: {
  374 + 'en-US': 'OthergjEBusStopLineChart',
  375 + 'zh-CN': '电子站牌单线路模拟图3'
  376 + },
  377 + title: '电子站牌单线路模拟图3',
  378 + icon: 'list',
  379 + component: OthergjEBusStopLineChart,
  380 + visible: true,
  381 + name: OthergjEBusStopLineChart.name
  382 + },
  383 +
  384 +
370 385 // {
371 386 // i18nTitle: {
372 387 // 'en-US': 'LineChart',
... ...