jjzjj

White Rose设计与架构的想法分享

七牛云 2023-03-28 原文

在七牛云校园黑客马拉松中,一款设计优秀、逻辑清晰的白板作品脱颖而出,获得第二名的好成绩,这就是来自郑州大学Since团队的White Rose白板,以下是他们的设计和架构分享。

一、前言

White Rose是参加七牛云hackathon比赛的作品,赛题的主要内容是开发一个「多人协作白板」,旨在鼓励在校大学生用编程创造价值。

赛题核心需求包含三个:

  1. 多人可以加入一个房间,同时进行绘画(尽可能多的形状随意绘制)
  2. 所有操作可以撤销和恢复
  3. 可以创建不同页面,支持只读模式(页面锁定后,所有人不可编辑)

二、产品设计

(1)愿景

基于hackathon的比赛要求,我调研了一些白板软件,这些软件不乏有一些「操作困难」「功能繁杂」等问题。所以,我定下一个产品愿景:「做一款从两岁到八十岁都能用的白板」

(2)追求

基于以上愿景我也设立了几条产品追求:「功能一键即达」「界面极致简洁」「内容高度自由」

作为乔布斯的粉丝,印象中乔布斯当年设计iphone时,要求工程师所有的功能操作不能超过3步,而对于白板一个单独的软件来说「进入」一步,「功能选择」一步,所以留给我的只有一步了。

(3)界面

为了让界面足够简洁,我将所有「扩展」功能全部放到了「上下左右」四个隐藏菜单里,从而让整个页面除了四个「必要数据」外,就只有一块“纯粹的白板”。

  • 对于两岁的小朋友来说进入就可以直接随意的涂鸦。
  • 对于八十岁老教授来说,这用起来跟教室的黑板一样。

下面分别是整体的界面效果。

无论多大的屏幕,什么形状的屏幕,都会无失真的自动扩张,因为它本质是一个高宽100%的矢量图。

因为不同屏幕的大小限制,这样的设计可能回导致小屏幕的人看到的内容没有大屏幕的「完整」。

对于有些软件的处理可能会有利用「拖拽页面」功能来确保每个人所能接收到的数据一致,这将意味着,用户的每次触屏操作,软件都要区分用户是想「拖拽页面」还是想「绘画」,而用户也需要在两个功能间频繁切换。

而我的理解:“白板”本质是一个大号的草稿纸,当我们给一群人讲一些内容的时候,「演讲者」可能随手会在白板上写下他讲的关键词「power point」,一般作为「演讲者」会写在一个大家都能看到的地方,这对「演讲者」不会增加太大负担,而对于「听众」一边听内容,还要一边还要拖拽页面去确认演讲者写在那里,这个负担更大。

回想一下我们在教室上课的时候,老师会尽量把内容写在中间靠上的位置,而不是底部,因为前排同学会挡到内容。

所以我摒弃了「拖拽页面」的功能。

当然「缩放」也不乏是另外一种解决方案,但是也会徒增操作者(缩放)的使用负担,并且还会引入另外一个问题就是「失真」。

关于颜色:

其实在选择白板的底色的时候,可能就是一个白色,但是其实白色也是五彩斑斓的,该用什么呢?

我想到一个词「青红皂白」,索性我就用「青红」和「皂白」调制了一个对眼睛更加柔和的 「青红皂白色」作为白板的底色。

(4)拓展功能

设计好了整个页面,接下来就是功能设计,我在设计界面的时候,预留了4个隐藏菜单栏来放拓展白板功能,为了让所有功能「一键即达」,并且更简单的使用,我采用了icon + 文字描述的方式,让用户更易理解。

整体展开如下图所示:

为什么是这样的摆放呢?

1、功能分类

根据赛题要求的功能,我将所有功能分为了四类。

  1. 形状拓展:用户可以选择圆、长方形、菱形、三角形、直线等形状。
  2. 颜色拓展:用户可以修改所有形状轨迹的颜色。
  3. 大小拓展:图形的大小和线条的粗细可以切换。
  4. 页面拓展:页面可以添加删除和切换,另外页面的内容支持撤销和恢复。

2、何处安放

我在想这个问题的时候,想象了在一张纸上作画的场景。

  • 一般我们习惯在桌子右侧放上各式各样的水彩笔,方便我们切换颜色,所以我将「颜色拓展」放在了右侧。
  • 我们习惯在桌子的上方和左侧放尺子、圆规之类的用来拓展图形和丰富绘画形状的工具,所以我将「形状拓展」「大小拓展」放在了左侧和上侧。
  • 当我们要做翻书、撕页等页面操作时,一般会从右下角开始,所以我将所有的「页面拓展」放置到了下侧,同时右下角有一个对应页面的页码,也因为大多数书的页码在这个位置。

(5)自由布局

上面讲到,我根据我个人的想法将各个功能进行了分类,并且按照我所理解的「更方便的布局」进行了排放,但在实际操作过程可能并不符合一些其他用户的操作习惯,比如:左撇子。

因此我将每个功能做了集成,并且可以随意的改变不同功能所在的位置,也就是所有的功能布局,用户可以根据自己的想法进行布局上的DIY。

三、架构设计

因为本次开发的周期只有21天,另外工作日的白天还需要上班,非常紧迫。所以需要采用非常简单且高效的架构设计,当然也需要考虑一些后续扩展的可能。

(1)整体架构

为了更好的「持续集成」我们采用自建的gitlab管理代理,并使用gitlab-runner完成自动化部署。

整体架构图如下图所示:

(2)交互模型

对于后端来说,为了更加高效的沟通,我将整个交互模型,定义为一个群聊,群内所有人的消息统一发给服务端,然后服务端再统一转发给其他人。

后端只需要确认三点:1.谁发的消息。2.发到那个群里的。3.消息类型。

整体交互结构如下:

{
"type": 1234,  // 操作类型
"fromId": 123, // 发送人id
"roomId": 1234,// 所在房间
"time": 152150025421564 //时间戳,前端不需要发送
"data": {} // 操作内容
} 

这样做的两个好处:

  1. 所有消息有一个统一的时序(即服务端时间)
  2. 后端完全无需关注「data」的具体内容。只根据type区分「接收」「分发」「存储」操作。

(3)data模型

data模型主要是前端所发送的和接收到的message里的data结构。

data里面该放什么?我将用户的所有操作定义为option,将用户的所有option放到data里面完成用户操作的转发。option的结构如下:

interface Op {
type: number // 页面操作or图形操作
graph?: {
op: number // 添加、旋转、缩放、平移
type?: string // 图形类别
key?: string // 图形所对应的key
page?: number // 图形所对应的页面
content?: any // 图形内容
}
page?: {
op: number //添加、删除、切换页面
key?: number // 页面对应的key
content?: any // 页面对应的内容
}
} 

这样的每个option,我们都会存放到操作栈里面,结合另外一个缓存栈,即可实现撤销和恢复。

(4)多人协同

对于多人的操作,其实是多个人对多个图形的操作,人与当前所操作的图形是一一对应的。

所以我通过一个令牌集的概念,来存放「所有的用户id」,以及每个用户当前「所操作的图形id」,这样就确定下来个每个用户正在操作什么。

不同用户的操作通过以下流程完成:

  1. 操作者设定当前所操作图形的id,并更新令牌集。
  2. 接收者同步更新令牌集。
  3. 操作者发送操作数据(option)。
  4. 接收者根据用户信息从令牌集中确定所操作的图形,再根据option修改具体的svg数据。

整体白板从产品的设计到架构的设计就结束了。

欢迎体验:http://whiterose.cf.since88.cn

前端代码:https://lab.since88.cn/whiterose/frontend

后端代码:https://lab.since88.cn/whiteros

有关White Rose设计与架构的想法分享的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  3. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  4. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  5. ruby-on-rails - 设计注册确认 - 2

    我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:

  6. ruby - Ruby 和 Ruby on Rails 中的三层架构 - 2

    我是一名决定学习Ruby和RubyonRails的ASP.NETMVC开发人员。我已经有所了解并在RoR上创建了一个网站。在ASP.NETMVC上开发,我一直使用三层架构:数据层、业务层和UI(或表示)层。尝试在RubyonRails应用程序中使用这种方法,我发现没有关于它的信息(或者也许我只是找不到它?)。也许有人可以建议我如何在RubyonRails上创建或使用三层架构?附言我使用ruby​​1.9.3和RubyonRails3.2.3。 最佳答案 我建议在制作RoR应用程序时遵循RubyonRails(RoR)风格。Rails

  7. ruby-on-rails - 设计通过 reset_password_token 获取用户 - 2

    我正在尝试创建密码规则来设计可恢复的密码更改。我通过passwords_controller.rb做了一个父类(superclass),但我需要在应用规则之前检查用户角色,但我所拥有的只是reset_password_token。 最佳答案 假设您的模型是用户:User.with_reset_password_token(your_token_here)Source 关于ruby-on-rails-设计通过reset_password_token获取用户,我们在StackOverflow

  8. ruby-on-rails - Rails 5,公寓和设计 : sign in with subdomains are not working - 2

    我已经使用Apartment设置了一个Rails5应用程序(1.2.0)和Devise(4.2.0)。由于某些DDNS问题,应用只能在app.myapp.com下访问(请注意子域app)。myapp.com重定向到app.myapp.com。我的用例是每个注册该应用的用户(租户)都应该通过他们的子域(例如tenant.myapp.com)访问他们的特定数据。用户不应限定在其子域内。基本上应该可以从任何子域登录。重定向到租户的正确子域由ApplicationController处理。根据Devise标准,登录页面位于app.myapp.com/users/sign_in。这就是问题开始的

  9. ruby-on-rails - 设计中的 ArgumentError::RegistrationsController#new 错误的参数数量(2 代表 0..1) - 2

    我在关注RyanbatesRailsCast的devise和omniauth(第235集-devise-and-omniauth-revised)。当我尝试使用Twitter登录时,标题中不断出现错误。defself.new_with_session(params,session)ifsession["devise.user_attributes"]new(session["devise.user_attributes"],without_protection:true)do|user|user.attributes=paramsuser.valid?end完整跟踪:C:/Ruby20

  10. ruby-on-rails - 使用用户或管理员模型和 Basecamp 样式子域设计登录 - 2

    我为Devise用户和管理员提供了不同的模型。我也在使用Basecamp风格的子域。除了我需要能够以用户或管理员身份进行身份验证的一些Controller和操作外,一切都运行良好。目前我有authenticate_user!在我的application_controller.rb中设置,对于那些只有管理员才能访问的Controller和操作,我使用skip_before_filter跳过它。不幸的是,我不能简单地指定每个Controller的身份验证要求,因为我仍然需要一些Controller和操作才能被用户或管理员访问。我尝试了一些方法都无济于事。看来,如果我移动authentica

随机推荐