当前位置: 首页 > 编程日记 > 正文

Web SCADA 电力接线图工控组态编辑器

前言

SVG并非仅仅是一种图像格式, 由于它是一种基于XML的语言,也就意味着它继承了XML的跨平台性和可扩展性,从而在图形可重用性上迈出了一大步。如SVG可以内嵌于其他的XML文档中,而SVG文档中也可以嵌入其他的XML内容,各个不同的SVG图形可以方便地组合, 构成新的SVG图形。这个 Demo 运用的技术基于 HTML5 的技术适应了只能电网调度、配电网运行监控与配电网运维管控,通过移动终端实现 Web SCADA 账上运维的时代需求。由于传统电力行业 CS 桌面监控系统一直到新一代 Web 和移动终端进化中,HT 是实施成本最低,开发和运行效率最高的前端图形技术解决方案。SVG 矢量图形大家都不会陌生了,尤其是在工控电信等领域,但是这篇文章并不是要制作一个新的绘制 SVG 图的编辑器,而是一个可绘制矢量图形并且对这个图形进行数据绑定的更高阶。

效果图

http://www.hightopo.com/demo/2deditor/HT-2D-Editor.html

代码实现

整体框架

根据上图看得出来,整个界面被分为五个部分,分别为 palette 组件面板,toolbar 工具条,graphView 拓扑组件,propertyPane 属性面板以及 treeView 树组件,这五个部分中的组件需要先创建出来,然后才放到对应的位置上去:

palette = new ht.widget.Palette();//组件面板
toolbar = new ht.widget.Toolbar(toolbar_config);//工具条
g2d = new ht.graph.GraphView(dataModel);//拓扑组件  
treeView = new ht.widget.TreeView(dataModel);//树组件
propertyPane = new ht.widget.PropertyPane(dataModel);//属性面板
propertyView = propertyPane.getPropertyView();//属性组件
rulerFrame = new ht.widget.RulerFrame(g2d);//刻度尺

这些布局,只需要结合 splitView 和 borderPane 进行布局即可轻松完成~其中 splitView 为 HT 中的 分割组件,参数1为放置在前面的 view 组件(可为左边的,或者上面的);参数2为放置在后面的 view 组件(可为右边的,或者下面的);参数3为可选值,默认为 h,表示左右分割,若设置为 v 则为上下分割;参数4即为分割的比例。borderPane 跟 splitView 的作用有些相似,但是在这个 Demo 中布局,结合这两种组件,代码看起来会更加清爽。

borderPane = new ht.widget.BorderPane();//边框面板
leftSplit = new ht.widget.SplitView(palette, borderPane, 'h', 260);//分割组件,h表示左右分割,v表示上下分割
rightSplit = new ht.widget.SplitView(propertyPane, treeView, 'v', 0.4);
mainSplit = new ht.widget.SplitView(leftSplit, rightSplit, 'h', -260);                                              borderPane.setTopView(toolbar);//设置边框面板的顶部组件为 toolbar
borderPane.setTopHeight(30);
borderPane.setCenterView(rulerFrame);//设置边框面板的中间组件为 rulerframe
mainSplit.addToDOM();//将 mainSplit 的底层 div 添加进 body 体中dataModel.deserialize(datamodel_config);//反序列化 datamodel_config 的内容,将json内容转为拓扑图场景内容
g2d.fitContent(true);

布局结束后,就要考虑每一个容器中应该放置哪些内容,我将这些内容分别封装到不同的函数中,通过调用这些函数来进行数据的显示。

Palette 组件面板

左侧的 Palette 组件面板需要向其内部添加 group 作为分组,然后再向组内添加节点。但是我们使用这个组件的最重要的一个原因是它能够拖拽节点,但是因为我们拖拽后需要在 graphView 拓扑组件中生成一个新的节点显示在拓扑图上,所以我将拖拽部分的逻辑写在了 graphView 拓扑组件的初始化函数中,这一小节就不做解释。

虽然说最重要的因素是拖拽,但是不可否认,这个组件在分类上也是非常直观:

如上图,我在 Palette 中做了三个分组:电力、食品加工厂以及污水处理。并在这些分组下面填充了很多属于该组类型的节点。我将这些分组的信息存储在 palette_config.js 文件中,由于三组中的信息量太大,这里只将一小部分的信息展示出来,看看是如何通过 json 对象来对分组进行数据显示的:

palette_config = {scene: {name: '电力',items: [{ name: '文字', image: '__text__', type: ht.Text },{ name: '箭头', image: 'symbols/arrow.json' },{ name: '地线', image: 'symbols/earthwire.json' }]},food: {name: '食品加工厂',items: [{ name: '间歇式流化床处理器', image: 'symbols/food/Batch fluid bed processor.json'},{ name: '啤酒瓶', image: 'symbols/food/Beer bottle.json'},{ name: '台式均质机', image: 'symbols/food/Batch fluid bed processor.json'}]},pumps: {name: '污水处理',items: [{ name: '3维泵', image: 'symbols/pumps/3-D Pump.json'},{ name: '18-惠勒卡车', image: 'symbols/pumps/18-wheeler truck 1.json'}]}     
};

通过遍历这个对象获取内部数据,显示不同的数据信息。当然,在获取对象的信息的时候,我们需要创建 ht.Group 类的对象,以及分组内部的 ht.Node 类的元素(这些元素都为组的孩子),然后将这些获取来的数据赋值到这两种类型的节点上,并且将这些节点添加到 Palette 的数据容器中:

function initPalette(){//初始化组件面板中的内容for(var name in palette_config){//从 palette_config.js 文件中获取数据var info = palette_config[name];var group = new ht.Group();//组件面板用ht.Group展示分组,ht.Node展示按钮元素
        group.setName(info.name);group.setExpanded(false);//设置group默认关闭palette.dm().add(group);//将节点添加到 palette 的数据容器中
        info.items.forEach(function(item){var node = new ht.Node();//新建 ht.Node 类型节点node.setName(item.name);//设置名称 用于显示在 palette 面板中节点下方说明文字node.setImage(item.image);//设置节点在 palette 面板中的显示图片//文本类型if (item.type === ht.Text) {//通过 json 对象中设置的 type 信息来获取当前信息为何种类型的节点,不同类型的节点有些属性设置不同
                node.s({'text': 'Text',//文本类型的节点需要设置这个属性显示文本的内容'text.align': 'center',//文本对齐方式'text.vAlign': 'middle',//文本垂直对齐方式'text.font': '32px Arial'//文本字体
                });}node.item = item;node.s({'image.stretch': item.stretch || 'centerUniform',//设置节点显示图片为填充的方式,这样不同比例的图片也不会因为拉伸而导致变形'draggable': item.draggable === undefined ? true : item.draggable,//设置节点是否可被拖拽
});                          group.addChild(node);//将节点设置为 group 组的孩子palette.dm().add(node);//节点同样也得添加到 palette 的数据容器中进行存储
        });}             
}

graphView 拓扑组件

前面说到了 Palette 组件中节点拖拽到 graphView 拓扑图形中,来看看这个部分是如何实现的。graphView 拓扑组件是 HT 非常重要的一个组件,了解它非常有必要。如果 Palette 中的 Node 的 draggable 属性设置为  true ,那么 Palette 可以自动处理 dragstart ,但是 dragover 和 dragdrop 事件需要我们处理,我们知道 IOS 和 Android 设备上并不支持 dragover 和 dragdrop 这类事件,所以 Palette 插件还提供了模拟的拖拽事件 handleDragAndDrop,可以完美兼容 PC 和手持终端。

function initGraphView(){       if(ht.Default.isTouchable){//判断是否为触屏可Touch方式交互palette.handleDragAndDrop = function(e, state) {//重写此方法可以禁用HTML5原生的Drag和Drop事件并启用模拟的拖拽事件if(ht.Default.containedInView(e, g2d)){//判断交互事件所处位置是否在View组件之上if(state === 'between'){e.preventDefault();//取消事件的默认动作。
                }else if(state === 'end'){//当state为end时,判断e是否在graphView的范围内,如果是,则创建Node
                    handleDrop(e);}}};}else{g2d.getView().addEventListener("dragover", function(e) {e.dataTransfer.dropEffect = "copy";e.preventDefault();});g2d.getView().addEventListener("drop", function(e) {handleDrop(e);});}
}function handleDrop(e){//被拖拽的元素在目标元素上同时鼠标放开触发的事件
    e.preventDefault();var paletteNode = palette.dm().sm().ld();//获取 palette 面板上最后选中的节点                 if (paletteNode) {   var item = paletteNode.item,image = item.image;data = g2d.getDataAt(e, null, 5);//获取事件下的节点var node = new (item.type || ht.Node)();node.setImage(image); //设置节点图片node.setName(item.name);  //设置节点名称node.p(g2d.lp(e));//设置节点的坐标为拓扑中的逻辑坐标 lp函数为将事件坐标转换为拓扑中的逻辑坐标node.s('label', '');//设置节点在 graphView 中底部不显示 setName 中的说明。因为 label 的优先级大于 name if(data instanceof ht.Group){//如果拖拽到“组类型”的节点上,那么直接设置父亲孩子关系node.setParent(data);//设置节点的父亲data.setExpanded(true);//展开分组}else{node.setParent(g2d.getCurrentSubGraph());}       g2d.dm().add(node);g2d.sm().ss(node);                                                     }                    
}  

我在 graphView 拓扑图的场景中央添加了一个 json 场景,通过 dm.deserialize(datamodel_config) 反序列化 json 场景内容导出的一个电信行业的图纸。HT 独特的矢量引擎功能满足电力行业设备种类繁多、设备图元和线路网络需无极缩放、绑定量测数据实时刷新等需求;三维呈现技术使得电力厂站和变压器等设备 3D 可视化监控成为可能。

treeView 树组件

至于树组件,树组件和 graphView  拓扑组件共用同一个 dataModl 数据容器,本来只需要创建出一个树组件对象,然后将其添加进布局容器中即可显示当前拓扑图形中的所有的数据节点,一般 HT 会将树组件上的节点分为几种类型进行显示,ht.Edge、ht.Group、ht.Node、ht.SubGraph、ht.Shape 等类型进行显示,但是这样做有一个问题,如果创建的节点非常多的话,那么无法分辨出那个节点是哪一个,也就无法快速地定位和修改该节点,会给绘图人员带来很大的困扰,所以我在 treeView 的 label 和 icon 的显示上做了一些处理:

// 初始化树组件
function initTreeView() {// 重载树组件上的文本显示treeView.getLabel = function (data) {if (data instanceof ht.Text) {return data.s('text');}else if (data instanceof ht.Shape) {return data.getName() || '不规则图形'}return data.getName() || '节点'};// 重载树组件上的图标显示var oldGetIconFunc = treeView.getIcon;treeView.getIcon = function (data) {if (data instanceof ht.Text) {return 'symbols/text.json';}var img = data.getImage();return img ? img : oldGetIconFunc.apply(this, arguments);}
}

propertyPane 属性面板

属性面板,即为显示属性的一个容器,不同的类型的节点可能在属性的显示上有所不同,所以我在 properties_config.js 文件中将几个比较常见的类型的属性存储到数组中,主要有几种属性: text_properties 用于显示文本类型的节点的属性、data_properties 所有的 data 节点均显示的属性、node_properties 用于显示 ht.Node 类型的节点的属性、group_properties 用于显示 ht.Group 类型的节点的属性以及 edge_properties 用于显示 ht.Edge 类型的节点的属性。通过将这些属性分类,我们可以对在 graphView 中选中的不同的节点类型来对属性进行过滤:

function initPropertyView(){//初始化属性组件               dataModel.sm().ms(function(e){//监听选中变化事件propertyView.setProperties(null);var data = dataModel.sm().ld();//针对不同类型的节点设置不同的属性内容if (data instanceof ht.Text) {//文本类型
            propertyView.addProperties(text_properties);return;}if(data instanceof ht.Data){// data 类型,所有的节点都基于这个类型
            propertyView.addProperties(data_properties);}                                        if(data instanceof ht.Node){// node 类型
            propertyView.addProperties(node_properties);}if(data instanceof ht.Group){//组类型
            propertyView.addProperties(group_properties);}if(data instanceof ht.Edge){//连线类型
            propertyView.addProperties(edge_properties);}     
    });                
}

数据绑定在属性栏中也有体现,拿 data_properties 中的“标签”和“可编辑”作为演示:

{name: 'name',//设置了 name 属性,如果没有设置 accessType 则默认通过 get/setName 来获取和设置 name 值displayName: '名称',//用于存取属性名的显示文本值,若为空则显示name属性值editable: true//设置该属性是否可编辑                       
}, 
{name: '2d.editable',//结合 accessType,则通过 node.s('2d.editable') 获取和设置该属性accessType: 'style',//操作存取属性类型displayName: '可编辑',//用于存取属性名的显示文本值,若为空则显示name属性值valueType: 'boolean',//布尔类型,显示为勾选框editable: true//设置该属性是否可编辑  
}

这两个属性比较有代表性,一个是直接通过 get/set 来设置 name 属性值,一个是通过结合属性的类型来控制 name 的属性值。只要在属性栏中操作“名称”和“可编辑”两个属性,就可以直接在拓扑图中看到对应的节点的显示情况,这就是数据绑定。当然,还可以对矢量图形进行局部的数据绑定,但是不是本文的重点,有兴趣的可以参考我的这篇文章 WebGL 3D 电信机架实战之数据绑定。

toolbar 工具栏

差点忘记说这个部分了,toolbar 上总共有 8 种功能,分别是选中编辑、连线、直角连线、不规则图形、刻度尺显示、场景放大、场景缩小以及场景内容导出 json。这 8 种功能都是存储在 toolbar_config.js 文件中的,通过绘制 toolbar 中的元素给每一个元素都添加上了对应的点击触发的内容,主要讲讲 CreateEdgeInteractor.js 创建连线的内容。

我们通过 ht.Default.def 自定义了 CreateEdgeInteractor 类,然后通过 graphView.setInteractors([ new CreateEdgeInteractor(graphView, 'points')]) 这种方式来添加 graphView 拓扑图中的交互器,可以实现创建连线的交互功能。

在 CreateEdgeInteractor 类中通过监听 touchend 放手后事件向 graphView 拓扑图中添加一个 edge 连线,可以通过在 CreateEdgeInteractor 函数中传参来绘制不同的连线类型,比如 “ortho” 则为折线类型:

var CreateEdgeInteractor = function (graphView, type) {CreateEdgeInteractor.superClass.constructor.call(this, graphView);   this._type = type;
};
ht.Default.def(CreateEdgeInteractor, DNDInteractor, {//自定义类,继承 DNDInteractor,此交互器有一些基本的交互功能handleWindowTouchEnd: function (e) {this.redraw();var isPoints = false;if(this._target){var edge = new ht.Edge(this._source, this._target);//创建一条连线,传入起始点和终点
            edge.s({'edge.type': this._type//设置连线类型 为传入的参数 type 类型 参考 HT for Web 样式手册
            });isPoints = this._type === 'points';//如果没有设置则默认为 points 连线方式if(isPoints){edge.s({'edge.points': [{//设置连线的点x: (this._source.p().x + this._target.p().x)/2,y: (this._source.p().y + this._target.p().y)/2
                    }]});                }edge.setParent(this._graphView.getCurrentSubGraph());//设置连线的父亲节点为当前子网this._graphView.getDataModel().add(edge); //将连线添加到拓扑图的数据容器中this._graphView.getSelectionModel().setSelection(edge);//设置选中该节点                        
        }this._graphView.removeTopPainter(this);//删除顶层Painterif(isPoints){resetDefault();//重置toolbar导航栏的状态
        }        }            
});

总结

一开始想说要做这个编辑器还有点怕怕的,就是感觉任务重,但是不上不行,所以总是在拖,但是后来整体分析下来,发现其实一步一步来就好,不要把步骤想得太复杂,什么事情都是从小堆到大的,以前我们用 svg 绘制的图形都可以在这上面绘制,当然,如果有需要拓展也完全 ok,毕竟别人写的编辑器不一定能够完全满足你的要求。这个编辑器虽说在画图上面跟别家无异,但是最重要的是它能够绘制出矢量图形,结合 HT 的数据绑定和动画,我们就可以对这些矢量图形中的每一个部分进行操作,比如灯的闪烁啊,比如人眨眼睛等等操作,至于这些都是后话了。有了这个编辑器我也能够更加快速地进行开发了~

相关文章:

IE6、IE7、IE8的CSS、JS兼容

Internet Explorer 6中查看使用 Microsoft JScript 的网页,可能会遇到web浏览器速度较慢的性能问题。原因是如果js脚本同时创建大量变量,jscript引擎执行垃圾收集算法时会监视脚本中变量分配的 数量、脚本中使用的文字值的数量和脚本中分配的字符串值的总…

中国电子学会青少年编程能力等级测试图形化一级编程题:海底世界

「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】或【Python】,即可进入。如果加入了之前的社群不需要重复加入。 海底世界 1. 准备工作 (1)背景:Underwater…

小说站 章节内容 ajax,第17章 作业分析与异步编程原理——2019年5月14日22:00

5月14日作业完善购物车的删除与编辑功能谈一下你对单线程,任务队列与事件循环, 同步与异步的理解单线程:单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。比如:JavaScript就是…

【转载】图像缩放与插值理论基础

图像的缩放 图像经过缩放后有可能在原图中招不到对应的像素点,这需要用图像插值来解决。 1.理论基础 假设图像的X轴方向缩放比例是Kx,Y轴方向的缩放比是Ky,则缩放后输出图像的点(x , y)对应原图中坐标(u , …

【组队学习】【32期】SQL编程语言

SQL编程语言 航路开辟者:王复振、杨煜、闫钟峰、杨梦迪、苏鹏、红星、张晋、汪健麟领航员:李云龙航海士:蒋志强、闫钟峰 基本信息 开源内容:https://github.com/datawhalechina/wonderful-sql开源内容:https://hub.…

查找手机型号云服务器,查找手机型号云服务器

查找手机型号云服务器 内容精选换一换您可以通过“应用管理”页面的应用列表,快速查看应用状态,及相关异常信息,如图1所示。包括:应用状态:即图1中的①应用异常信息:即图1中的②云服务器异常信息&#xff1…

浅谈25种设计模式(4/25)(此坑未填)

设计模式汇总 创建型模式 这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用新的运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。 工厂模式(Factory Pattern)抽象工厂模式&#xf…

C#学习笔记8:HTML和CSS基础学习笔记

<!-- 1、<P>...</P>段落标签 2、<br/>折行标签。 3、<img src"" height"*px" width"*px" alt"图片描述">。 注意&#xff1a;不能写成<img ></img>的形式。 4、html注释&#xff1a;<!-- …

青少年编程竞赛交流群周报(第043周)

2021年12月26日&#xff08;周日&#xff09;晚20:00我们在青少年编程竞赛交流群开展了第四十三期直播活动。 一、直播内容 我们直播活动的主要内容如下&#xff1a; 讲解了上次测试中小朋友们做错的题目 Scratch青少年编程能力等级测试模拟题&#xff08;四级&#xff09;。…

数据库备份到文件服务器,数据库文件备份到云服务器上

数据库文件备份到云服务器上 内容精选换一换目前数据库服务器备份Agent安装包需要提交工单进行获取。当前仅支持x86计算类型的服务器&#xff0c;暂不支持鲲鹏计算类型的服务器。用户需要启用数据库备份前&#xff0c;需先在弹性云服务器上更改安全组和安装客户端。本章节指导用…

android String.format

资源创建&#xff1a; <!-- 多参数验证 --> <string name"text">截止到:%1$tc\n销售量比去年增长了%2$d%%\n在这里我对所有奋斗的兄弟姐妹表示感谢\n对表现最优秀 的%3$s等伙伴我们予以奖励\n奖励为价值%4$-9.4e的新马泰游\n希望大家再接再厉额!<…

【组队学习】【32期】数据可视化(Matplotlib)

数据可视化&#xff08;Matplotlib&#xff09; 航路开辟者&#xff1a;杨剑砺、杨煜、耿远昊、李运佳、居凤霞领航员&#xff1a;王万航海士&#xff1a;范歆琦、张文恺 基本信息 开源内容&#xff1a;https://github.com/datawhalechina/fantastic-matplotlib开源内容&…

没有完美的人或事

下面以苹果手机为例&#xff0c;说明一个问题当实际值与期望值不符合的时候&#xff0c;人会出现的感情状况 公众人物与普通人 像公众人物类的&#xff0c;在公众面前肯定要表现正式一点的&#xff0c;这个是必须的&#xff0c;这个是有非常大的影响力的。我们的期望值大于或等…

如何理解分时系统的四个特征

多路性 服务多个用户 独立性 各用户独立 及时性 当一个任务暂时不能执行&#xff0c;CPU如子弹上膛般立刻换上另一任务&#xff0c;决不空闲 交互性 即人机交互 分时操作系统服务多个用户&#xff0c;并且让每个用户觉得自己是唯一的用户&#xff08;它怎么做到这一点的&#x…

中国电子学会青少年编程能力等级测试图形化一级编程题:小狗进圈

「青少年编程竞赛交流群」已成立&#xff08;适合6至18周岁的青少年&#xff09;&#xff0c;公众号后台回复【Scratch】或【Python】&#xff0c;即可进入。如果加入了之前的社群不需要重复加入。 小狗进圈 小狗非常听话&#xff0c;收到命令能在舞台上向右移动&#xff0c;如…

Swift 值类型和引用类型的内存管理

1、内存分配 1.1 值类型的内存分配 在 Swift 中定长的值类型都是保存在栈上的&#xff0c;操作时不会涉及堆上的内存。变长的值类型&#xff08;字符串、集合类型是可变长度的值类型&#xff09;会分配堆内存。 这相当于一个 “福利”&#xff0c;意味着你可以使用值类型更快速…

jquery获取浏览器宽高

满足获取各种高的需求 $(document).ready(function() { alert($(window).height()); //浏览器时下窗口可视区域高度 alert($(document).height()); //浏览器时下窗口文档的高度 alert($(document.body).height());//浏览器时下窗口文档body的高度 alert($(document.body).oute…

操作系统的管理功能

1.CPU/处理器管理 2.存储器/内存管理 3.文件管理 4.I/O设备管理 一般来讲为以上四大管理功能&#xff0c;如果有第五 5.作业管理

秦州:西瓜书 + 南瓜书 吃瓜系列 13. 降维与度量学习(上)

吃瓜教程——西瓜书南瓜书 Datawhale南瓜书是经典机器学习教材《机器学习》&#xff08;西瓜书&#xff09;的公式推导解析指南&#xff0c;旨在让在学习西瓜书的过程中&#xff0c;再也没有难推的公式&#xff0c;学好机器学习。 内容属性&#xff1a;机器学习&#xff08;理…

flash 入门课知识小结

一、 几种类型帧的小结&#xff1a;&#xff08;关键帧、空白关键帧、普通帧&#xff09;1. 特点 帧——是进行flash动画制作的最基本的单位&#xff0c;每一个精彩的flash动画都是由很多个精心雕琢的帧构成的&#xff0c;在时间轴上的每一帧都可以包含需要显示的所有内容&…

VUE解决微信签名,SPA微信invalid signature问题,完美处理

深度解决方案&#xff0c;包教不包会&#xff0c;只因为踩坑无数&#xff0c;希望大家能有所收获 前端小菜鸟&#xff0c;因为项目要对接微信的jssdk&#xff0c;对接就需要签名认证&#xff0c;但是无奈安卓和IOS各有各的坑&#xff0c;本篇文章只讨论签名&#xff0c;和一个分…

如何打开写好的jpetstore

1.停止正在占用8080端口的应用 打开cmd窗口&#xff0c;输入netstat -ano | find “:8080”&#xff0c;查到pid 输入tasklist /fi “pid eq pid”&#xff0c;查到应用的名字 打开任务管理器&#xff0c;停止应用 2.第二步就比较神奇了 打开tomcat的bin目录&#xff0c;先sh…

打通Fedora19的ssh服务

Fedora19的SSH服务是默认关闭的&#xff0c;安装后我们需要打通它。 首先&#xff0c;编辑/etc/ssh/sshd_config&#xff0c;把下面黑体字部分打开注释&#xff0c;如下&#xff1a; # $OpenBSD: sshd_config,v 1.89 2013/02/06 00:20:42 dtucker Exp $# This is the ssh…

使用hql动态创建对象问题

前段时间由于需求要添加报表数据&#xff0c;调整ireport后&#xff0c;打印pdf文件出现数据错位的情况&#xff0c;调试发现不是ireport问题&#xff0c;就查看了后台传送的数据&#xff0c;最后发现传送的对象属性值已经就是错位的&#xff0c;那就是获取对象时出的问题&…

秦州:西瓜书 + 南瓜书 吃瓜系列 14. 降维与度量学习(下)

吃瓜教程——西瓜书南瓜书 Datawhale南瓜书是经典机器学习教材《机器学习》&#xff08;西瓜书&#xff09;的公式推导解析指南&#xff0c;旨在让在学习西瓜书的过程中&#xff0c;再也没有难推的公式&#xff0c;学好机器学习。 内容属性&#xff1a;机器学习&#xff08;理…

从用户角度看,DBMS应当提供哪些功能?

1.定义&#xff1a;提供DDL&#xff0c;供用户使用数据库定义语言创建其想要建立的表&#xff0c;定义三级模式&#xff0c;两级映像。 2.操作&#xff1a;提供DML&#xff0c;供用户可以实现增删改查&#xff08;追加、删除、更新、查询&#xff09;等操作。 3.控制&#xff1…

groovy–运算符重载

Groovy支持运算符重载&#xff0c;各种运算符被映射到普通的java对象的方法调用&#xff0c;这就使得开发者可以利用运算符重载的优势来编写自己的Java或者groovy对象。 下面的表格描述了groovy中的操作符所映射到的方法&#xff1a; Operator Method a b a.plus(b) a – …

【组队学习】【32期】吃瓜教程——西瓜书+南瓜书

吃瓜教程——西瓜书南瓜书 航路开辟者&#xff1a;谢文睿、秦州领航员&#xff1a;陈伟峰航海士&#xff1a;谢文睿、秦州 基本信息 开源内容&#xff1a;https://github.com/datawhalechina/pumpkin-bookB 站视频&#xff1a;https://www.bilibili.com/video/BV1Mh411e7VU内…

关键字this引用

要点提示&#xff1a; 关键字this引用独享自身。他也可以在构造方法内部调用另一个类的其他构造方法。 关键字this是指向调用对象本身的引用名。可以用this关键字引用对象的实例成员。 复制代码 例如&#xff1a;下面a的代码使用this来显示地引用独享的radius以及调用他的getAr…

数据库系统DBS的特点

在数据库系统发明以前&#xff0c;人们使用文件系统来管理数据。文件系统具有以下不足&#xff1a; 1.数据冗余&#xff08;与数据共享相对&#xff09;和非一致性&#xff08;文件格式不相容&#xff09; 2.程序依赖于数据&#xff08;新任务要写新程序&#xff09; 3.数据孤立…