Commit a63fe967c308b46aa1830e225ea4022b02eac01a

Authored by 徐烜
1 parent 7183693d

临港公交电子站牌项目

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